工廠模式之簡單工廠模式

来源:https://www.cnblogs.com/cjaaron/archive/2018/05/11/9026974.html
-Advertisement-
Play Games

簡單工廠模式簡介 工廠模式有一種非常形象的描述,建立對象的類就如一個工廠,而需要被建立的對象就是一個個產品;在工廠中加工產品,使用產品的人,不用在乎產品是如何生產出來的。從軟體開發的角度來說,這樣就有效的降低了模塊之間的耦合。 簡單工廠的作用是實例化對象,而不需要客戶瞭解這個對象屬於哪個具體的子類。 ...


簡單工廠模式簡介

工廠模式有一種非常形象的描述,建立對象的類就如一個工廠,而需要被建立的對象就是一個個產品;在工廠中加工產品,使用產品的人,不用在乎產品是如何生產出來的。從軟體開發的角度來說,這樣就有效的降低了模塊之間的耦合。

簡單工廠的作用是實例化對象,而不需要客戶瞭解這個對象屬於哪個具體的子類。簡單工廠實例化的類具有相同的介面或者基類,在子類比較固定並不需要擴展時,可以使用簡單工廠。如資料庫生產工廠就是簡單工廠的一個應用

  • 優點:可以使用戶根據參數獲得對應的類實例,避免了直接實例化類,降低了耦合性;
  • 缺點:可實例化的類型在編譯期間已經被確定,如果增加新類 型,則需要修改工廠,不符合OCP(開閉原則)的原則。簡單工廠需要知道所有要生成的類型,當子類過多或者子類層次過多時不適合使用。

面向對象的要點

  • 面向對象三大特性:封裝、繼承、多態。
  • 通過封裝、繼承、多態把程式耦合降低。
  • 業務邏輯和界面邏輯分開。

程式設計的要點

  • 程式應該做到:(1)可維護;(2)可復用;(3)可擴展;(4)靈活性好。
  • 可維護:就是說代碼一處更改,不能產生連鎖反應,不能影響其他地方。
  • 可復用:儘量減少重覆性代碼。
  • 可擴展:如果要擴展新的功能、新的業務,則只需要增加新的類就好了,不對已有的類和邏輯產生影響。插拔式的應用

實例分析

題目:

用任意一種面向對象語言實現一個計算器控制台程式。要求輸入兩個數和運算符號,得到結果。

設計有缺陷的代碼

#!/usr/bin/env python
# _*_ coding utf-8 _*_
#Author: aaron

num1 = int(input('請輸入第一個數:'))
op =input('請輸入運算符(+ - * /):')
num2 = int(input('請輸入第一個數:'))

if op == '+':
    res = num1 + num2
elif op == '-':
    res = num1 - num2
elif op == '*':
    res = num1 * num2
elif op == '/':
    res = num1 / num2

print('運算結果為:',res)

 存在的問題

  • 業務邏輯和界面邏輯沒有分開
  • 業務邏輯有漏洞(除法中num2沒有做非零判斷)
  • 不具有擴展性(無法添加新功能,eg:加入平方運算,再加入一條“elif語句”是很糟糕的修改方式,下文詳細敘述)
  • 可維護性差(eg:加入平方運算時,很可能修改其他地方的源代碼,有人就說了,怎麼可能,不就是再加入一條“elif語句”嗎?是的,反這種低級錯誤的概率很小,我所說的是惡意修改源代碼。當然,又有人反駁了,不就是添加一種運算嗎,我修改其他運算幹嘛?是的,非常正確。但你想過沒,如果我們這裡的“if語句”不是做運算符的判斷,而是做某個公司的薪資計算呢,那修改代碼的程式員會不會惡意將和自己相關的地方修改了呢?這也解釋了不具有擴展性的問題了)

完善後的代碼

設計思路分析

1. 首先,搞清楚業務中容易發生變化的部分。在本應用中,要求計算兩個數的運算結果,那麼要進行什麼樣的運算,這就是一個容易發生變化的部分。例如,我們現在只想實現加減乘除運算,後期又想增加開根或者求餘運算。那麼如何應對這種需求帶來的變化。在程式設計的時候就應該考慮到程式的可維護性、可擴展性、代碼的可復用性、靈活性等等。
 
2. 例如現在這個運算器只有加減乘除四種運算。首先建一個Operation類,這個類是各種具體運算類(加減乘除)的父類,主要是接受用戶輸入的數值。該類如下:

class Operation():  
    def __init__(self,NumberA=0,NumberB=0):  
        self.NumberA = NumberA  
        self.NumberB = NumberB  
  
    def GetResult(self):  
        pass  

 3. 然後是具體的運算類:Add、Sub、Mul、Div。他們都繼承了Operation類,並且重寫了getResult()方法。這樣就可以用多態性降低不同業務邏輯的耦合度,修改任何一種運算類都不會影響其他的運算類。具體類的代碼如下:

class AddOp(Operation):  
    def GetResult(self):  
        return self.NumberB + self.NumberA  
  
class MinusOp(Operation):  
    def GetResult(self):  
        return self.NumberA - self.NumberB  
  
class MultiOp(Operation):  
    def GetResult(self):  
        return self.NumberA * self.NumberB  
  
class DivideOp(Operation):  
    def GetResult(self):  
        try:  
            return 1.0*self.NumberA / self.NumberB  
        except ZeroDivisionError:  
            raise  

 4.  那麼如何讓計算器知道我是要用哪一種運算呢?也就是說到底要實例化哪一個具體的運算類,Add?Sub?Mul?Div?這時就應該考慮用 一個單獨的類來做這個創造具體實例的過程,這個類就是工廠類。如下:

class OperationFatory():  
    def ChooseOperation(self,op):  
        if op == '+':  
            return AddOp()  
        if op == '-':  
            return MinusOp()  
        if op == '*':  
            return MultiOp()  
        if op == '/':  
            return DivideOp()  

 5. 這樣,用戶只要輸入運算符,工廠類就可以創建合適的實例,通過多態性,即返回給父類的方式實現運算結果。客戶端代碼如下:

if __name__ == '__main__':  
    ch = ''  
    while not ch=='q':   
        NumberA = eval(raw_input('Please input number1:  '))  
        op = str(raw_input('Please input the operation:  '))  
        NumberB = eval(raw_input('Please input number2:  '))  
        OPFactory = OperationFatory()  
        OPType = OPFactory.ChooseOperation(op)  
        OPType.NumberA = NumberA  
        OPType.NumberB = NumberB  
        print 'The result is:',OPType.GetResult()  
        print '\n#--  input q to exit any key to continue'  
        try:  
            ch = str(raw_input())  
        except:  
            ch = ''  

 

完整版代碼:

# -*-coding:UTF-8-*-  
from abc import ABCMeta,abstractmethod

class Operation():
	def __init__(self,NumberA=0,NumberB=0):
		self.NumberA = NumberA
		self.NumberB = NumberB

	def GetResult(self):
		pass

class AddOp(Operation):
	def GetResult(self):
		return self.NumberB + self.NumberA

class MinusOp(Operation):
	def GetResult(self):
		return self.NumberA - self.NumberB

class MultiOp(Operation):
	def GetResult(self):
		return self.NumberA * self.NumberB

class DivideOp(Operation):
	def GetResult(self):
		try:
			return 1.0*self.NumberA / self.NumberB
		except ZeroDivisionError:
			raise

class OperationFatory():
	def ChooseOperation(self,op):
		if op == '+':
			return AddOp()
		if op == '-':
			return MinusOp()
		if op == '*':
			return MultiOp()
		if op == '/':
			return DivideOp()

if __name__ == '__main__':
	ch = ''
	while not ch=='q': 
		NumberA = eval(raw_input('Please input number1:  '))
		op = str(raw_input('Please input the operation:  '))
		NumberB = eval(raw_input('Please input number2:  '))
		OPFactory = OperationFatory()
		OPType = OPFactory.ChooseOperation(op)
		OPType.NumberA = NumberA
		OPType.NumberB = NumberB
		print 'The result is:',OPType.GetResult()
		print '\n#--  input q to exit any key to continue'
		try:
			ch = str(raw_input())
		except:
			ch = ''

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 先最簡單的代碼 安裝 npm install express app.js 代碼內容 打開 localhost:2334埠可以看到 在上一個豐富點的代碼,包含 swig模版引擎,靜態資源載入,mongoose使用 我在上面代碼中做了詳細的註寫,還會詳細完善 github地址:https://git ...
  • 在介紹js中Object.defineProperty()和defineProperties()之前,我們瞭解下js中對象兩種屬性的類型:數據屬性和訪問器屬性。 數據屬性 數據屬性包含一個數據的位置,在這個位置可以讀取和寫入。其有4個描述其行為的特性 [[Configurable]] 表示能否通過d ...
  • JavaScript中對數組和數組API的認識 一、數組概念: 數組是JavaScript中的一類特殊的對象,用一對中括弧“[]”表示,用來在單個的變數中存儲多個值。在數組中,每個值都有一個對應的不重覆的索引值。自動匹配索引值的數組稱為索引數組,自定義索引值的數組稱為關聯數組(又叫哈希數組)。以下均 ...
  • 1、身份證 2、軍官證 3、護照 4、營業執照 5、駕照 6、組織機構代碼證 7、台胞證 8、港澳通行證 ...
  • 本文內容: 面向對象 常見內置對象及操作 首發日期:2018-05-11 面向對象: JavaScript 是面向對象的編程語言 (OOP)。OOP 語言使我們有能力定義自己的對象和變數類型。 對象是一種帶有屬性和方法的特殊變數類型。 如何創建對象: 使用內置對象類型創建一個內置對象:變數名=new... ...
  • 本文內容: 函數 函數的定義方式 函數的調用方式 函數的參數 匿名函數 函數中的this 事件 常見事件 綁定事件 首發日期:2018-05-11 函數: 函數的定義方式: 函數可以有參數,參數為局部變數,無需要var修飾: 函數可以有返回值: 函數的調用方式:除了自執行函數,其他函數都要手動調用 ... ...
  • 全局 DOM 變數 你可能已經知道,聲明一個全局變數(使用 var 或者不使用)的結果並不僅僅是創建一個全局變數,而且還會在 global 對象(在瀏覽器中為 window )中創建一個同名屬性。 還有一個不太為人所知的事實是:由於瀏覽器演進的歷史遺留問題,在創建帶有 id 屬性的 DOM 元素時也 ...
  • 點擊當前標簽給其添加class,兄弟標簽class刪除 演示地址: https://xibushijie.github.io/static/addClass.html ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...