標籤:參考資料 分離 3.0 @class 設計 ret eth 面向 port
寫在前面的話
"""讀書的時候上過《設計模式》這一門課,當時使用的教材是程傑老師的《大話設計模式》,使用的語言是C#,學過課程之後初期深感物件導向思想的偉大,但是很少應用到實際開發中。後來我接觸了Python,現在工作中用到最多的也是Python,或許是因為Python的便利性,我寫的很多指令碼/程式都還是面向過程編程,缺少物件導向的思想在裡邊。因此,我打算重讀程傑老師的《大話設計模式》並用Python進行實踐。""" by ZH乳酪——張賀
題目
用一種物件導向語言實現一個計算機控制台程式, 要求輸入兩個數和運算子號(+-*/), 得到結果.
基礎版本
a = int(input("input a number:"))b = str(input("input a operater(+ - * /):"))c = int(input("input a number:"))if b == "+": print(a+c)elif b == "-": print(a-c)elif b == "*": print(a*c)else b == "/": print(a/c)
input a number:16input a operater(+ - * /):*input a number:232
點評
- 變數命名不規範
- 無用的if條件判斷太多
- 除法運算中未考慮第二個數字為0的情況
改進版本1.0——規範代碼
number_a = int(input("input a number:"))operator = str(input("input a operater(+ - * /):"))number_b = int(input("input a number:"))if operator == "+": print(number_a + number_b)elif operator == "-": print(number_a - number_b)elif operator == "*": print(number_a * number_b)elif operator == "/": if number_b != 0: print(number_a / number_b) else: print("With operator '/', the second number can not be zero.")else: print("Wrong operator.")
input a number:12input a operater(+ - * /):/input a number:0With operator '/', the second number can not be zero.
點評
- 沒有使用物件導向的思想
- 只滿足當前需求, 不易維護, 不易擴充, 不易複用, 不夠靈活
為什麼活字印刷術能位列四大發明?主要是其方法的思想。
- 文章改字方便, 可維護
- 一個字可以重複使用, 可複用
- 文章加字容易, 可擴充
- 文章改版只需移動活字, 靈活性好
複製?複用?
如果做一個帶圖形化介面的計算機,上邊的代碼需要再寫一次。為了避免這樣,需要將商務邏輯
與介面邏輯
分開,降低耦合度。
改進版本2.0——利用封裝解耦
class Operation(): def __init__(self): self.result = None def get_result(self, number_a, number_b, operator): if operator == "+": self.result = number_a + number_b elif operator == "-": self.result = number_a - number_b elif operator == "*": self.result = number_a * number_b elif operator == "/": if number_b != 0: self.result = number_a / number_b else: print("With operator '/', the second number can not be zero.") else: print("Wrong operator.") return self.resultnumber_a = int(input("input a number:"))operator = str(input("input a operater(+ - * /):"))number_b = int(input("input a number:"))operation = Operation()print(operation.get_result(number_a, number_b, operator))
input a number:12input a operater(+ - * /):+input a number:1224
點評
- 僅僅用到了封裝, 還沒用到繼承和多態。
緊耦合?松耦合?
如果要支援一個開根號運算,上邊的代碼需要改動包括加減乘除在內的get_result
函數,應該將加減乘除運算分離, 修改其中一個不影響其他的幾個。那麼就需要定義一個Operator基類, 將get_result
定義為虛函數,然後通過繼承和多態,分別實現加減乘除四個子類,每個子類中定義虛函數的實現邏輯。
參考資料: Python中的多態與虛函數
改進版本3.0——簡單原廠模式
from abc import ABCMeta, abstractmethodclass Operation(): __metaclass__ = ABCMeta def __init__(self): self.result = None @abstractmethod def get_result(self): pass class AddOperation(Operation): def get_result(self, number_a, number_b): self.result = number_a + number_b return self.result class SubOperation(Operation): def get_result(self, number_a, number_b): self.result = number_a - number_b return self.result class MulOperation(Operation): def get_result(self, number_a, number_b): self.result = number_a * number_b return self.result class DivOperation(Operation): def get_result(self, number_a, number_b): if number_b == 0: print("With operator '/', the second number can not be zero.") return self.result self.result = number_a / number_b return self.result
如何執行個體化?——簡單原廠模式
現在加減乘除的實現邏輯已經進一步隔離,之後即使增加一個開根號運算子,也和加減乘除無關。那麼如何去執行個體化這些類呢?可以用簡單原廠模式
。
class OperationFactory(): @classmethod def create_operate(self, operator): oper = None if operator == "+": oper = AddOperation() elif operator == "-": oper = SubOperation() elif operator == "*": oper = MulOperation() elif operator == "/": oper = DivOperation() else: print("Wrong operator.") return oper
通過上邊的簡單工廠,輸入運算子號,就可以執行個體化出對應的對象。下邊是用戶端的代碼。
number_a = int(input("input a number:"))operator = str(input("input a operater(+ - * /):"))number_b = int(input("input a number:"))oper = OperationFactory.create_operate(operator)print(oper.get_result(number_a, number_b))
input a number:12input a operater(+ - * /):-input a number:120
點評
- 商務邏輯與介面邏輯隔離,不關心是控制台程式還是GUI程式
- 不同運算邏輯隔離,一個運算子的增刪改操作不會影響其他運算
- 物件導向思想的封裝,繼承,多態都有所體現
- 易維護,易擴充,易複用
[Python設計模式] 第1章 計算機——簡單原廠模式