開始以前須要引入一些項目設計知識,如接口,抽象方法抽象類,組合,程序設計原則等,我的理解項目的合理設計可增長其靈活性,下降數據之間的耦合性,提升穩定性,下面介紹一些預備知識 css
其實py中沒有接口這個概念。要想實現接口的功能,能夠經過主動拋出異常來實現python
接口做用:對派生類起到限制的做用編程
例:app
#!/usr/bin/env python # -*- coding: utf-8 -*- """ 接口,python中的接口,經過在父類中主動拋出異常實現 接口的做用:起到了限制的做用 """ class IFoo: def fun1(self): pass raise Exception("----") class Bar(IFoo): def fun1(self): #方法名必須和父類中的方法名相同,否則沒辦法正常執行,會拋出異常 print("子類中若是想要調用父類中的方法,子類中必需要有父類中的方法名") def fun2(self): print("test") obj = Bar() obj.fun2()
抽象類,抽象方法是普通類和接口的綜合,便可以繼承也能夠起到限制做用ide
因爲python 自己沒有抽象類、接口的概念,因此要實現這種功能得abc.py 這個類庫,具體實現方法以下 :函數
#!/usr/bin/env python # -*- coding: utf-8 -*- """ 抽象類,抽象方法 抽象類,抽象方法是普通類和接口的綜合,便可以繼承也能夠起到限制做用 """ import abc class Foo(metaclass=abc.ABCMeta): def fun1(self): print("fun1") def fun2(self): print("fun2") @abc.abstractclassmethod def fun3(self): pass class Bar(Foo): def fun3(self): print("子類必須有父類的抽象方法名,否則會拋出異常") obj = Bar() obj.fun1() obj.fun2() obj.fun3()
python中「多用組合少用繼承」,由於繼承的偶合性太強,能夠把基類,當作參數傳入派生類中,用於解偶測試
如;spa
#!/usr/bin/env python # -*- coding: utf-8 -*- #繼承 class Animals: def eat(self): print(self.Name + " eat") def drink(self): print(self.Name + " drink") class Person(Animals): def __init__(self, name): self.Name = name def think(self): print(self.Name + " think") obj = Person("user1") obj.drink() obj.eat() obj.think()
class Animals: def __init__(self,name): self.Name = name def eat(self): print(self.Name + " eat") def drink(self): print(self.Name + " drink") class Person: def __init__(self, obj): self.obj = obj def eat(self): self.obj.eat() def think(self,name): print(name + " think") animals = Animals("animals") obj = Person(animals) obj.think("person") obj.eat()
剛接觸理解的比較淺顯設計
像上一例中,若是有多層關係時,須要傳入多個對象,爲了解決這個問題就引入了依賴注入,如上例在Person類實例化時自動傳入Animals對象3d
那麼,在引入依賴注入時先了解一下python類實例化過程當中背後作了什麼事情
class Foo: def __init__(self): self.name = 111 def fun(self) print(self.name) obj = Foo() #obj是Foo的實例化對象
在python中一切皆對象,Foo是經過type類建立的
例:
#!/usr/bin/env python # -*- coding:utf-8 -*- class MyType(type): def __call__(cls, *args, **kwargs): obj = cls.__new__(cls, *args, **kwargs) obj.__init__(*args, **kwargs) return obj class Foo(metaclass=MyType): def __init__(self, name): self.name = name def f1(self): print(self.name)
解釋器解釋: 1.遇到 class Foo,執行type的__init__方法 1.Type的init的方法裏作什麼麼呢?不知道 obj = Foo(123) 3.執行Type的 __call__方法 執行Foo類的 __new__方法 執行Foo類的 __init__ 方法
先來了解幾個概念
new 和 __init()和__metaclass__:
__new__函數是實例一個類所要調用的函數,每當咱們調用obj = Foo()來實例一個類時,都是先調用__new__()
而後再調用__init__()函數初始化實例. __init__()在__new__()執行後執行,
類中還有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化建立,因此,咱們能夠爲 __metaclass__ 設置一個type類的派生類,從而查看 類 建立的過程。
那麼依賴注入的實現方法,自定義一個type方法,實例化類的時候指定由自定義的type方法建立,具體實現方法以下:
#!/usr/bin/env python # -*- coding: utf-8 -*- # 依賴注入應用 #DI class Mapper: __mapper_relation ={} @staticmethod def register(cls,value): Mapper.__mapper_relation[cls] = value @staticmethod def exist(cls): if cls in Mapper.__mapper_relation: return True return False @staticmethod def value(cls): return Mapper.__mapper_relation[cls] class MyType(type): def __call__(self, *args, **kwargs): obj = self.__new__(self, *args, **kwargs) arg_list = list(args) if Mapper.exist(self): value=Mapper.value(self) arg_list.append(value) obj.__init__(*arg_list, **kwargs) return obj #定義由誰來實例化 class Foo(metaclass=MyType): def __init__(self,name): self.name = name def f1(self): print(self.name) class Bar(metaclass=MyType): def __init__(self,name): self.name = name def f1(self): print(self.name) Mapper.register(Foo,"test1") Mapper.register(Bar,"test12") f=Foo() print(f.name)
一個對象只對一個元素負責
優勢;
消除耦合,減少因需求變化引發代碼僵化
2.開放封閉原則
對擴展開放,對修改關閉
優勢:
按照OCP原則設計出來的系統,下降了程序各部分之間的耦合性,其適應性、靈活性、穩定性都比較好。當已有軟件系統須要增長新的功能時,
不須要對做爲系統基礎的抽象層進行修改,只須要在原有基礎上附加新的模塊就能實現所須要添加的功能。增長的新模塊對原有的模塊徹底沒有影響或影響很小,
這樣就無須爲原有模塊進行從新測試
如何實現 ?
在面向對象設計中,不容許更必的是系統的抽象層,面容許擴展的是系統的實現層,因此解決問題的關鍵是在於抽象化。
在面向對象編程中,經過抽象類及接口,規定具體類的特徵做爲抽象層,相對穩定,不須要作更改的從面能夠知足「對修改關閉」的原則;而從抽象類導出的具體 類能夠
改變系統 的行爲,從而知足「對擴展開放的原則"
3.里氏替換原則
5.依賴倒置原則
注:
Infrastructure 目錄:公共組件目錄
Model:業務邏輯處理目錄
Repository: 數據倉庫及數據處理目錄
Statics:靜態文件目錄如(css,js,images等)
UIAdmin: UI層
Views:模板文件目錄
Application.py : 服務啓動文件