Skip to content

8. Uygulama alıştırması - Katmanlı mimariye sahip ile [IMPOTS]

Burada 4.1. paragrafta açıklanan alıştırmayı ele alıyoruz. 4.3. paragrafta açıklanan metin dosyaları içeren sürümden yola çıkıyoruz. Bu örneği nesnelerle işlemek için üç katmanlı bir mimari kullanacağız:

  • [dao] katmanı (Veri Erişim Nesnesi), verilere erişimden sorumludur. İlerleyen bölümlerde bu veriler önce bir metin dosyasında, ardından MySQL veritabanında bulunacaktır;
  • [metier] katmanı iş sorunlarıyla, bu örnekte vergi hesaplamasıyla ilgilenir. Verilerle ilgilenmez. Veriler iki kaynaktan gelebilir:
    • kalıcı veriler için [dao] katmanı;
    • kullanıcı tarafından sağlanan veriler için [console] katmanı.
  • [console] katmanı ise kullanıcı etkileşimlerini yönetir.

Bundan sonra, [dao] ve [metier] katmanları, her biri bir sınıf kullanılarak uygulanacaktır. [console] katmanı ise ana program tarafından uygulanacaktır.

[dao] katmanının tüm uygulamalarının, vergi hesaplaması için gerekli olan üç veri tablosunu (sınırlar, coeffR, coeffN) içeren bir tuple döndüren getData() yöntemini sunduğu varsayılacaktır; bu tuple, vergi hesaplaması için gerekli olan üç veri dizisini içerir. Diğer dillerde buna arayüz denir. Bir arayüz, bu arayüzü uygulayan sınıfların sahip olması gereken yöntemleri (burada getData) tanımlar.

[metier] katmanı, yapıcı işlevinin parametresi olarak [dao] katmanına bir referans alan bir sınıf tarafından uygulanacaktır; bu da iki katman arasındaki iletişimi sağlayacaktır.

8.1. [dao] katmanı

Uygulama için gerekli olan farklı sınıfları tek bir impots.py dosyasında bir araya getireceğiz. Bu dosyadaki nesneler daha sonra bunlara ihtiyaç duyan komut dosyalarına içe aktarılacaktır.

Öncelikle, 4.3. paragrafındaki örnekte olduğu gibi verilerin bir metin dosyasında bulunduğu durumdan başlayacağız.

[ImpotsFile] sınıfının kodu (impots.py), [dao] katmanını uygulayan şu şekildedir:


# -*- coding=utf-8 -*-

import math, sys

# --------------------------------------------------------------------------
# özel istisna sınıfı
class ImpotsError:
    pass

# --------------------------------------------------------------------------
class Utilitaires:
    """classe de fonctions utilitaires"""
    def cutNewLineChar(self,ligne):
        # varsa satır sonu işaretini silin
        l=len(ligne)
        while(ligne[l-1]=="\n" or ligne[l-1]=="\r"):
            l-=1
        return(ligne[0:l])

# --------------------------------------------------------------------------
class ImpotsFile:
    def __init__(self,IMPOTS):
        # IMPOTS: sınır tablolarının verilerini içeren dosyanın adı, coeffR, coeffN
        # dosya açılır
        data=open(IMPOTS,"r")
        # Yardımcı Programlar nesnesi
        u=Utilitaires()
        # 3 tablonun oluşturulması - IMPOTS dosyasındaki 3 satırın sözdizimsel olarak doğru olduğu varsayılır
        # -- 1. satır
        ligne=data.readline()
        if ligne== '':
            raise ImpotsError("La premiere ligne du fichier {0} est absente".format(IMPOTS))
        limites=u.cutNewLineChar(ligne).split(":")
        for i in range(len(limites)):
            limites[i]=int(limites[i])
        # -- satır 2
        ligne=data.readline()
        if ligne== '':
            raise ImpotsError("La deuxieme ligne du fichier {0} est absente".format(IMPOTS))
        coeffR=u.cutNewLineChar(ligne).split(":")
        for i in range(len(coeffR)):
            coeffR[i]=float(coeffR[i])
        # -- satır 3
        ligne=data.readline()
        if ligne== '':
            raise ImpotsError("La troisieme ligne du fichier {0} est absente".format(IMPOTS))
        coeffN=u.cutNewLineChar(ligne).split(":")
        for i in range(len(coeffN)):
            coeffN[i]=float(coeffN[i])
        # son
        (self.limites,self.coeffR,self.coeffN)=(limites,coeffR,coeffN)

    def getData(self):
        return (self.limites, self.coeffR, self.coeffN)

Notlar:

  • 7-8. satırlar: Exception sınıfından türetilen bir ImpotsError sınıfı tanımlanmaktadır. Bu sınıf, Exception sınıfına hiçbir şey eklememektedir. Bu sınıf, yalnızca özel bir istisna sınıfına sahip olmak için kullanılır. İleride bu sınıf zenginleştirilebilir;
  • 11-18. satırlar: bir yardımcı yöntemler sınıfı. Burada cutNewLineChar yöntemi, bir karakter dizisindeki olası satır sonu işaretini kaldırır;
    1. satır: Dosyanın açılması, IOError istisnasını tetikleyebilir;
  • satır 32, 39, 46: özel istisna ImpotsError tetiklenir;
  • Kod, 4.3. paragrafındaki örnekte incelenen kodla benzerdir.

8.2. [metier] katmanı

[metier] katmanını uygulayan [ImpotsMetier] (impots.py) sınıfı şu şekildedir:


class ImpotsMetier:

    # yapıcı
    # [dao] katmanına bir işaretçi alınır
    def __init__(self, dao):
        self.dao=dao

    # vergi hesaplaması
    # --------------------------------------------------------------------------
    def calculer(self,marie,enfants,salaire):
        # evli: evet, hayır
        # çocuklar: çocuk sayısı
        # maaş: yıllık maaş

        # hesaplama için gerekli veriler [dao] katmanından istenir
        (limites, coeffR, coeffN)=self.dao.getData()

       # pay sayısı
        marie=marie.lower()
        if(marie=="oui"):
            nbParts=float(enfants)/2+2
        else:
            nbParts=float(enfants)/2+1
        # en az 3 çocuk varsa 1/2 hisse daha eklenir
        if enfants>=3:
            nbParts+=0.5
        # vergilendirilebilir gelir
        revenuImposable=0.72*salaire
        # aile katsayısı
        quotient=revenuImposable/nbParts
        # takip eden döngüyü durdurmak için sınır tablosunun sonuna eklenir
        limites[len(limites)-1]=quotient
        # vergi hesaplaması
        i=0
        while quotient>limites[i] :
            i=i+1
        # aile katsayısı sınır tablosunun sonuna yerleştirildiği için, önceki döngü
        # sınır tablosunun dışına çıkamaz
        # artık vergiyi hesaplayabiliriz
        return math.floor(revenuImposable*(float)(coeffR[i])-nbParts*(float)(coeffN[i]))

Notlar:

  • 5-6. satırlar: Sınıfın oluşturucusu, [dao] katmanına bir referans parametre olarak alır;
    1. satır: Vergi hesaplamasına olanak tanıyan verileri almak için [dao] katmanının getData yöntemi kullanılır;
  • kodun geri kalanı, 4.3. paragrafındaki örnekte incelenen kodla benzerdir.

8.3. [console] katmanı

[console] (impots-03) katmanını uygulayan komut dosyası şöyledir:


# -*- coding=utf-8 -*-

# Impots* sınıf modülünü içe aktarma
from impots import *

# ------------------------------------------------ ana işlev
# sabitlerin tanımlanması
DATA="data.txt"
RESULTATS="resultats.txt"
IMPOTS="impots.txt"

# vergi hesaplaması için gerekli veriler IMPOTS dosyasına yerleştirildi
# tablolar için her bir satırda şu biçimde
# val1:val2:val3,...

# [metier] katmanının örneklenmesi
try:
    metier=ImpotsMetier(ImpotsFile(IMPOTS))
except (IOError, ImpotsError) as infos:
    print ("Une erreur s'est produite : {0}".format(infos))
    sys.exit()

# verilerin okunması
try:
    data=open(DATA,"r")
except:
    print "Impossible d'ouvrir en lecture le fichier des donnees [DATA]"
    sys.exit()

# sonuç dosyasının açılması
try:
    resultats=open(RESULTATS,"w")
except:  
    print "Impossible de creer le fichier des résultats [RESULTATS]"
    sys.exit()

# yardımcı programlar
u=Utilitaires()

# veri dosyasının geçerli satırını işleme
ligne=data.readline()
while(ligne != ''):
    # varsa satır sonu işaretini kaldırma
    ligne=u.cutNewLineChar(ligne)
    # satırı oluşturan "evli:çocuk sayısı:maaş" şeklindeki 3 alanı alınır
    (marie,enfants,salaire)=ligne.split(",")
    enfants=int(enfants)
    salaire=int(salaire)
    # vergi hesaplanır
    impot=metier.calculer(marie,enfants,salaire)
    # sonuç yazılır
    resultats.write("{0}:{1}:{2}:{3}\n".format(marie,enfants,salaire,impot))
    # yeni bir satır okunur
    ligne=data.readline()
# dosyaları kapatıyoruz
data.close()
resultats.close()

Notlar:

    1. satır: Sınıf tanımlarını içeren impots.py dosyasındaki tüm nesneler içe aktarılır. Bu işlem tamamlandıktan sonra, bu nesneler komut dosyasıyla aynı dosyada bulunuyormuş gibi kullanılabilir;
  • 17-21. satırlar: Olası istisnalar yönetilerek hem [dao] katmanı hem de [metier] katmanı örneklenir;
    1. satır: [dao] katmanını, ardından da [metier] katmanını oluşturuyoruz. [metier] katmanına ilişkin referansı kaydediyoruz;
    1. satır: Meydana gelebilecek iki istisna işlenir;
  • kodun geri kalanı, 4.3. paragrafındaki örnekte incelenen kodla benzerdir.

8.4. Résultats

Bunlar, tablolar ve dosyalar içeren sürümlerde daha önce elde edilenlerle aynıdır.

impots.txt veri dosyası:

12620:13190:15640:24740:31810:39970:48360:55790:92970:127860:151250:172040:195000:0
0:0.05:0.1:0.15:0.2:0.25:0.3:0.35:0.4:0.45:0.5:0.55:0.6:0.65
0:631:1290.5:2072.5:3309.5:4900:6898.5:9316.5:12106:16754.5:23147.5:30710:39312:49062

data.txt veri dosyası:

oui,2,200000
non,2,200000
oui,3,200000
non,3,200000
oui,5,50000
non,0,3000000

Elde edilen sonuçlara ait resultats.txt dosyaları:

oui:2:200000:22504.0
non:2:200000:33388.0
oui:3:200000:16400.0
non:3:200000:22504.0
oui:5:50000:0.0
non:0:3000000:1354938.0