簡單工廠模式(simple factory)及程式碼實現
簡單工廠模式屬於 建立型模式,是用來建立物件的模式,在建立物件時,客戶端程式碼無需知道建立邏輯,只要知道傳輸什麼引數即可
實現簡單工廠模式思路(按照如下程式碼示例 思考):
我的業務需求有2個,分別為 計算買入手續費,賣出手續費,分析後發現 獲取 手續費費率 規則 相同,而且 都需要當日淨值
既然都是 手續費,且有相同部分,便可抽象出 一個 手續費基類,包含買入/賣出相同部分,計算手續費規則不同,則可 讓子類實現;
在客戶端程式碼 需要計算 買入或賣出手續費 時,無需考慮 手續費相關類的實現細節,只需 輸入不同引數即可返回 買入或賣出 工廠類
既然如此,便可 通過 簡單工廠模式實現:
簡單工廠模式優點:
- 符合 開閉原則 ; 無需更改現有客戶端程式碼, 便可在程式中引入新的手續費型別如 分紅
- 符合 單一職責原則 ; 一個具體工廠類只負責計算一種手續費
- 客戶端呼叫 方便; 只需不同入參,便可獲得對應 物件
- 避免建立者和具體產品之間的緊密耦合 ; 如 如下程式碼中的 handing_fee_factory建立著函式 只負責根據不同入參返回對應類,而類的具體實現則不在此處
簡單工廠模式缺點:
- 當 有很多 工廠類時,建立者程式碼 會有很多條件判斷的程式碼,因此而變得複雜; 可能 會有 很多 if else;或者 通過dict來實現引數和具體類的對映;
如下幾個示例為 相關工廠模式實現的程式碼
1.簡單工廠模式實現的 計算 基金買入/賣出 手續費 demo (相關計算方式已經簡化,實際程式碼要複雜很多)
# -*- coding: utf-8 -*-
"""
(C) Guangcai Ren <rgc@bvrft.com>
All rights reserved
create time '2020/10/25 15:58'
Usage:
簡單工廠模式 實現 基金 買入/賣出 手續費 計算規則
"""
from abc import ABC, abstractmethod
from copy import deepcopy
class HandlingFeeBase(ABC):
"""手續費基類"""
@abstractmethod
def __init__(self, rule, net_val):
"""
:param rule: 手續費規則
:param net_val: 當日淨值
"""
self.rule = rule
self.net_val = net_val
def _get_handling_fee_rate(self, benchmark_num):
"""
獲取手續費費率
此乃刪減後部分 計算手續費規則,不能直接使用在業務程式碼中
根據手續費規則list倒敘 後,根據 每個規則第一個資料 大小判斷,如果大於等於 則 直接返回 對應費率
:param benchmark_num: 買入金額 或 賣出 的時間天數
:return:
[
[0,100000,0.015], # 手續費 >=0,<100000,費率 0.015
[100000,1000000,0.005],# 手續費 >=100000,<1000000,費率 0.005
[1000000,-1,0] # 手續費 >=1000000,<無限大,費率 0
]
如果 買入了 100001 元,倒敘校驗後 發現 100000<=100001<1000000 所以返回 0.005費率
如果 買入了 10000 元,倒敘校驗後 發現 100000<=100000<1000000 所以返回 0.005費率
"""
rule = deepcopy(self.rule)
rule.reverse()
for rule_list in rule:
handling_fee_rate = rule_list[2]
min_num = rule_list[0]
max_num = rule_list[1]
# -1表示正無窮大
if max_num == -1:
max_num = float('inf')
if min_num <= benchmark_num < max_num:
return handling_fee_rate
@abstractmethod
def calculate(self):
"""
計算 手續費 方法,由子類實現
:return:
"""
pass
class BuyHandingFee(HandlingFeeBase):
"""買入手續費 工廠類"""
def __init__(self, rule, net_val, **kwargs):
"""
初始化
:param rule:
:param net_val:
:param buy_amount:
"""
super(BuyHandingFee, self).__init__(rule, net_val)
self.buy_amount = kwargs.get('buy_amount')
self.handling_fee_rate = self._get_handling_fee_rate(self.buy_amount)
def calculate(self):
"""
計算買入手續費
:return:
"""
return self.buy_amount * self.handling_fee_rate
class SellHandingFee(HandlingFeeBase):
"""賣出手續費 工廠類"""
def __init__(self, rule, net_val, **kwargs):
"""
初始化
:param rule:
:param net_val:
:param kwargs:
"""
super(SellHandingFee, self).__init__(rule, net_val)
self.sell_days = kwargs.get('sell_days') # 距離賣出間隔天數
self.sell_share = kwargs.get('sell_share') # 賣出份額
# 根據間隔天數 算出手續費費率
self.handling_fee_rate = self._get_handling_fee_rate(self.sell_days)
def calculate(self):
"""
計算賣出手續費
:return:
"""
# 根據 賣出淨值 * 賣出份額 * 費率 計算 賣出手續費
return self.net_val * self.sell_share * self.handling_fee_rate
def handing_fee_factory(rule, net_val, **kwargs):
"""
簡單工廠模式的建立著,可以是類或者函式,根據不同入參,返回對應 類
根據入參 獲取對應 買入 或 賣出 手續費計算類
:param rule:
:param net_val:
:param kwargs:
:return:
"""
if 'sell_days' in kwargs and 'sell_share' in kwargs:
print('返回 賣出 類')
return SellHandingFee(rule, net_val, **kwargs)
elif 'buy_amount' in kwargs:
print('返回 買入 類')
return BuyHandingFee(rule, net_val, **kwargs)
raise Exception('引數錯誤,無法獲取對應手續費 物件')
if __name__ == '__main__':
"""
客戶端(client)程式碼 呼叫 簡單工廠模式實現的 計算買入/賣出 手續費
客戶端只需填寫引數,便根據不同引數返回對應計算手續費物件,客戶端 不用考慮具體手續費實現邏輯
在 後續 新增不同手續費計算類 如 分紅,也符合 開閉原則(抽象出一層,達到 對 擴充套件開放,對修改封閉),原有客戶端計算買入/賣出的程式碼無需修改
"""
# 計算買入手續費
handing_fee_obj = handing_fee_factory([[0, 100000, 0.015], [100000, -1, 0.001]], 1.5, **{'buy_amount': 1000})
print('買入手續費金額為:', handing_fee_obj.calculate())
# 計算賣出手續費
handing_fee_obj = handing_fee_factory([[0, 7, 0.015], [7, -1, 0.001]], 1.5, **{'sell_share': 100, 'sell_days': 5})
print('賣出手續費金額為:', handing_fee_obj.calculate())
2.Flask中 通過 工廠模式實現的 根據不同環境引數,返回對應配置類
# -*- coding: utf-8 -*-
"""
(C) Guangcai Ren <rgc@bvrft.com>
All rights reserved
create time '2020/10/25 15:58'
Usage:
簡單工廠模式 實現 flask 配置
"""
import logging
from abc import ABC
from flask import Flask
class Config(ABC):
"""
配置基類
"""
pass
class LocalConfig(Config):
"""
本地配置類
"""
ENV = 'local'
DEBUG = True
LOG_LEVEL = logging.DEBUG
class DevelopConfig(Config):
"""
開發服配置類
"""
ENV = 'develop'
DEBUG = True
LOG_LEVEL = logging.DEBUG
class ProductConfig(Config):
"""
生產服配置類
"""
ENV = 'product'
DEBUG = False
LOG_LEVEL = logging.INFO
# 建立者,此處通過簡單的 dict資料結構 便可實現
config = {
"LOCAL": LocalConfig,
"DEV": DevelopConfig,
"PROD": ProductConfig
}
def create_app(config_name):
"""
客戶端 程式碼部分,根據不同入參,獲取對應 配置類
:param config_name:
:return:
"""
app = Flask(__name__)
app.config.from_object(config[config_name])
return app
if __name__ == '__main__':
# 本地配置
app = create_app('LOCAL')
print(app.config.get('ENV'))
# 生產配置
app = create_app('PROD')
print(app.config.get('ENV'))
3.mysql配置中,根據不同入參返回對應 資料庫型別 的 物件
def connect(db, *arg, **kwargs):
"""
此函式便是一個簡單版本的 工廠模式, 根據不同的入參,返回不同型別的 資料庫連結字串(其實最好 返回的是 不同的 資料庫物件),此處copy 的網上的程式碼;
而且 這種過於簡單的方式是否符合 簡單工廠模式(仁者見仁智者見智)
"""
db = db.lower()
dbname = kwargs['db']
if db == 'mysql':
result = "mysql+pymysql://{username}:{password}@{server}/{dbname}".format(username = kwargs['username'], password = kwargs['password'], server = kwargs['server'], dbname=dbname)
elif db == 'postgresql:
result = 'postgresql://{username}:{passwrod}@{server}/{dbname}'.format(susername = kwargs['username'], password = kwargs['password'], server = kwargs['server'], dbname=dbname)
return result
總結:
需要理解 簡單工廠模式的思想核心:不同引數,返回 同一種抽象層下的不同物件 即可;不要 過於在意 實現的具體方式;要站在 程式碼設計的 角度去思考 只要滿足 工廠模式的 條件 寫出的程式碼便是工廠模式;
如 簡單工廠模式的建立者 可以是 類,可以是 函式 甚至可以是 一個dict ;
腦子需要靈活,不用在乎程式碼實現形式,只要符合設計模式 核心思想(意境) 便是完人;
相關連結:
https://refactoringguru.cn/design-patterns/factory-method
https://refactoringguru.cn/design-patterns/factory-method/python/example
https://github.com/youngsterxyf/mpdp-code/blob/master/chapter1/factory_method.py
相關文章
- 簡單工廠模式(Simple Factory Pattern)模式
- 簡單工廠模式( Simple Factory Pattern )模式
- 設計模式筆記:簡單工廠模式(Simple Factory)設計模式筆記
- 使用C# (.NET Core) 實現簡單工廠(Simple Factory) 和工廠方法設計模式 (Factory Method Pattern)C#設計模式
- PHP設計模式(一)簡單工廠模式 (Simple Factory For PHP)PHP設計模式
- JAVA設計模式之 簡單工廠模式【Simple Factory Pattern】Java設計模式
- 設計模式的征途—2.簡單工廠(Simple Factory)模式設計模式
- 我所理解的設計模式(C++實現)——簡單工廠模式(Simple Factory Pattern)設計模式C++
- 簡單工廠模式—>工廠模式模式
- 工廠模式之簡單工廠模式模式
- 設計模式-C#實現簡單工廠模式設計模式C#
- 簡單工廠和工廠模式模式
- 簡單工廠模式、工廠模式、抽象工廠模式比較模式抽象
- 簡單工廠模式和抽象工廠模式模式抽象
- 工廠模式(簡單工廠模式)快速理解模式
- 簡單工廠模式模式
- Python 實現工廠模式、抽象工廠,單例模式Python模式抽象單例
- 設計模式-簡單工廠、工廠方法模式、抽象工廠模式設計模式抽象
- 建立型:工廠模式-簡單工廠模式
- 簡單工廠和工廠方法模式模式
- 簡單工廠、工廠方法和抽象工廠模式抽象模式
- 1、簡單工廠模式實現計算器功能模式
- 一篇搞定工廠模式【簡單工廠、工廠方法模式、抽象工廠模式】模式抽象
- 【Java】簡單工廠模式、工廠模式、介面卡模式Java模式
- 設計模式實戰 – 抽象工廠模式(Abstract Factory Pattern)設計模式抽象
- 設計模式實戰 - 抽象工廠模式(Abstract Factory Pattern)設計模式抽象
- 設計模式 | 簡單工廠模式及典型應用設計模式
- 簡單工廠模式--SimpleFactory模式
- C# 設計模式(1)——簡單工廠模式、工廠模式、抽象工廠模式C#設計模式抽象
- 簡單工廠、工廠模式初學習模式
- 《設計模式》 - 2. 工廠模式( Factory )設計模式
- 設計模式--工廠模式Factory(建立型)設計模式
- Java設計模式之工廠模式(Factory)Java設計模式
- Factory Method 工廠方法模式(建立型模式)模式
- 設計模式之工廠模式!深入解析簡單工廠模式,工廠方法模式和抽象工廠模式設計模式抽象
- java 簡單工廠模式(實現一個計算器)Java模式
- 簡單工廠模式、工廠方法模式和抽象工廠模式有何區別?模式抽象
- 設計模式 - 簡單工廠模式設計模式