關於簡單工廠模式與開閉原則的討論(1)
說個老生常談的問題的了,就是簡單工廠模式到底是不是違背了開閉原則?
在討論之前,先重溫下什麼是開閉原則。
開閉原則(open/closed principle)的定義是,software entities (classes, modules, functions) should be open for extension, but closed for modification,一個類開放它的拓展,關閉它的修改,即一個類可以允許拓展它的功能,而不允許修改它的原始碼。
先舉個簡單的例子,關於開閉原則的,看下面一段程式碼
上面的問題在於,如果策劃要加一個buff種類,你必須又加一個if-else的條件判斷,這樣會造成無休止的修改此類,然後再次測試此類能否正常執行,包括引用到它的類又能否正常執行。如果到後期系統越變越龐大,則非常難維護。class DefenseBuff { private int m_buffType; public int BuffType { get { return m_buffType; } set { m_buffType = value; } } public int GetDiscountDamage(int TotalDamage) { if (m_buffType == 1) { return TotalDamage - 100; } else { return TotalDamage - 50; } } }
這就是違背了開閉原則。
如果我們改成下面這樣:用繼承和多型的方式,如果加了新的型別,我們只要建立一個新的子類就行了,這樣就不會違背開閉原則
或者我們可以重Excel資料表中讀資料,然而在現實開發中,策劃一般把數值寫在Excel表中的,不會向上面那樣寫死的,然而我們也不需要再修改程式碼,而策劃可以任意修改數值和增加型別。class DefenseBuff { public virtual int GetDiscountDamage(int TotalDamage) { return TotalDamage; } } class SilverDefenseBuff : DefenseBuff { public override int GetDiscountDamage(int TotalDamage) { return base.GetDiscountDamage(TotalDamage) - 50; } } class GoldDefenseBuff : DefenseBuff { public override int GetDiscountDamage(int TotalDamage) { return base.GetDiscountDamage(TotalDamage) - 100; } }
class DefenseBuff { private int m_buffType; public int BuffType { get { return m_buffType; } set { m_buffType = value; } } public DefenseBuff(int buffType) { m_buffType = buffType; } public int GetDiscountDamage(int TotalDamage) { return BuffTable.GetType(m_buffType).DiscountDamage;//從excel配置表讀取資料 } } var player = WorldMap.Instance.GetSelfPlayer(); Monster m = WorldMap.Instance.GetMonsterPool().GetAt(0); DefenseBuff bf = new DefenseBuff(PlayerProperty.Instance.GetMetaData(player.ID).buffType); player.Damage(bf.GetDiscountDamage(MonsterTable.GetType(m.ID)).AttackDamage));
說完了開閉原則,現在來說一下簡單工廠模式,看下面程式碼:
using System;
enum MonsterType
{
SKELETON,
GHOUST,
EVIL,
CACODEMON
}
abstract class Monster
{
public abstract int AttackDamage { get; }
}
class Skeleton : Monster
{
public override int AttackDamage
{
get
{
return 10;
}
}
}
class Ghoust : Monster
{
public override int AttackDamage
{
get
{
return 20;
}
}
}
class Evil : Monster
{
public override int AttackDamage
{
get
{
return 50;
}
}
}
class Cacodemon : Monster
{
public override int AttackDamage
{
get
{
return 100;
}
}
}
static class MonsterFactory
{
public static Monster Create(MonsterType monster_type)
{
switch(monster_type)
{
case MonsterType.SKELETON:
return new Skeleton();
case MonsterType.GHOUST:
return new Ghoust();
case MonsterType.EVIL:
return new Evil();
case MonsterType.CACODEMON:
return new Cacodemon();
}
}
}
var player = WorldMap.Instance.GetSelfPlayer();
var monster = MonsterFactory.Create(MonsterType.SKELETON);
player.Damage(monster.AttackDamage);
上述程式碼的問題就在於,如果策劃要加一個新的怪物類,那我們就必須增加一個Swith-Case條件,就必須修改MonsterFactory的內部程式碼,這個其實在一定程度上也已經違背了開閉原則
如果改成下面的方式,類似於抽象工廠的方式,如果新加了一個怪物類,我們只要新增一個MonsterInfo的子類即可,就不會違背開閉原則了。
public abstract class MonsterInfo
{
public abstract Monster CreateMonster();
}
public class SkeletonInfo : MonsterInfo
{
public override Skeleton CreateMonster()
{
return new Skeleton();
}
}
public class GhoustInfo : MonsterInfo
{
public override Ghoust CreateMonster()
{
return new Ghoust();
}
}
public static class MonsterFactory
{
public static Monster Create(MonsterInfo aInfo)
{
return aInfo.CreateMonster();
}
}
var player = WorldMap.Instance.GetSelfPlayer();
var monster = MonsterFactory.Create(new SkeletonInfo());
player.Damage(monster.AttackDamage);
或者我們使用泛型,會更簡潔方便
static class MonsterFactory<T> where T : Monster,new()
{
public static Monster Create()
{
return new T();
}
}
var player = WorldMap.Instance.GetSelfPlayer();
var monster = MonsterFactory<Skeleton>.Create();
player.Damage(monster.AttackDamage);
或者使用反射的方式:
public static class MonsterFactory
{
public static Monster Create(Type monsterType)
{
return Activator.CreateInstance(monsterType) as Monster;
}
public static Monster Create(string monsterType)
{
Type type = Assembly.GetExecutingAssembly().GetType(monsterType);
return Activator.CreateInstance(type) as Monster;
}
}
var player = WorldMap.Instance.GetSelfPlayer();
var monster1 = MonsterFactory.Create(typeof(SkeletonInfo));
var monster2 = MonsterFactory.Create("Ghoust");
player.Damage(monster1.AttackDamage);
player.Damage(monster2.AttackDamage);
綜上所述,我們基本可以認為帶過多的switch-case或if-else的簡單工廠模式是違背開閉原則的,會增加程式碼的耦合度,會造成當系統變得龐大時,極其難以維護。
其實我們有很多的方法,可以繞開過多swith-case或if-else的條件,以滿足開閉原則來實現簡單的工廠模式。
關於更多的工廠模式和開閉原則,我們今後再繼續討論,今天先說這麼多。如果有什麼錯誤或不對的,歡迎大家多多指正。
相關推薦
關於簡單工廠模式與開閉原則的討論(1)
說個老生常談的問題的了,就是簡單工廠模式到底是不是違背了開閉原則? 在討論之前,先重溫下什麼是開閉原則。 開閉原則(open/closed principle)的定義是,software entities (classes, modules, functions) sho
【設計模式】六大原則之一(單一職責與開閉原則)
【前言】 最近在學習設計模式,設計模式是面向物件程式設計的。設計模式有6大原則,而實際上都是互補的,也就是說一些原則需要利用另一些原則來實現自己。下面來簡單的介紹一下六大原則其中之二 【單一職責原則】 1、單一職責原則的由來 初學者在程式設計
簡單工廠模式與工廠方法模式
interface ace nal tor sim str bre sys 對象比較 簡單工廠 定義:簡單工廠模式屬於創建型模式,其又被稱為靜態工廠方法模式,這是由一個工廠對象決定創建出哪一種產品類的實例 工廠類 public class CamputerFacto
【設計模式】簡單工廠模式與工廠方法模式詳細解讀
1.前言 設計模式,各具特色,今天在此總結一下常見模式中 簡單工廠模式與工廠方法模式的區別與聯絡 2.兩種模式概要 1. 簡單工廠模式 2. 工廠方法模式 工廠方法模式又稱
淺談設計模式之簡單工廠模式與策略模式
本文主要是關於面向物件程式設計(OOP)的設計模式,瞭解優秀軟體設計的演變過程比學習優秀的設計本身更有價值,因為設計演變的過程蘊藏著巨大的智慧,是一代一代程式設計師的思想的結晶。通過學習設計模式,設計出易於維護、擴充套件、複用以及靈活性好的程式;使用多型、繼承、
android 二級快取(單一原則與開閉原則)
import android.content.Context; import android.graphics.Bitmap; import java.io.IOException; /** * SD卡快取 */ public class DiskCache imple
簡單工廠模式與工廠方法模式以及Mybatis中工廠模式的使用
一、簡單工廠模式 Java是一門面向物件的語言。有很多時候我們需要去生產物件,工廠模式就是我們生產物件的一種方式。 比如這樣一個場景: 我們需要做一個兩個數之間的運算,但我們不知道使用者究竟要使用哪種運算子對其進行運算。我們就可以使用工廠模式,對使用者的選擇做一個判斷,從
設計模式之開閉原則
override cati 聖誕 turn extension span 核心 inter open 開放封閉原則(Open Close Principle,簡稱OCP)盡量通過擴展軟件實體的行為來實現變化,而不是通過修改已有的代碼來實現變化 原始定義:Software
工廠模式與OO設計原則
如果把建立看作一個職責,那麼系統中的哪個物件應該擁有這個職責呢?如果把建立看作知識,那麼建立知識應該放置在什麼地方呢?說到職責我們不得不說一下著名的GRASP原則: GRASP是通用職責分配軟體模式(General Responsibility Assignment Soft
一、Java設計模式之開閉原則
定義:一個軟體實體,如類、模組和函式應該對擴充套件開放,對修改關閉 用抽象構建框架,用實現擴充套件細節 優點:提高軟
設計模式之軟體開發原則(1)開閉原則和依賴倒置原則
開閉原則 定義 所謂開閉原則就是一個軟體實體如類、模組和函式應該對擴充套件開放、對修改關閉。 強呼叫抽象構建框架,實現實現拓展細節。 有優點是提高軟體的複用性和易維護展性。是面向物件的最基本原則。 依賴倒置原則 定義 高層模組不應該依賴底層模組,二者都應該依賴其抽象。 抽象不應該依賴細節:細節應該
軟體架構與模式(依賴注入 控制反轉 依賴倒置原則 開閉原則 單一職責原則 介面隔離原則 里氏代換原則)
名詞解釋: 依賴: 一個獨立元素的變化會影響到相關的元素 派生: 一個類是由其他類衍生出的,子類繼承了基類的結構(屬性的名詞和型別)方法 抽象: 去掉每個不重要的細節,專
大話設計模式之四:1~5章(簡單工廠模式 、策略模式、單一職責原則、開放封閉原則 、依賴倒轉原則)
注:《大話設計模式》這本書很好的介紹了設計模式,其對應的原始碼是C#語言寫得,跑在visual studio上,所以自己先安裝visual studio ,然後將原始碼跑一跑,這樣能深刻的理解《大話設
設計模式六大原則(6):開閉原則
思考 外部 編程人員 恰恰 單一職責 何事 適應 擴展 分享 開閉原則 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對
設計模式筆記1:簡單工廠模式
1.3 簡單 修改 作用 面向對象 對象 面向 tro 計算 如果想成為一名更優秀的軟件設計師,了解優秀軟件設計的演變過程比學習優秀設計本身更有價值。 1.1 面向對象的好處 通過封裝、繼承多態把程序的耦合度降低,使用設計模式使得程序更加靈活,容易修改,易於復用
初識設計模式1:簡單工廠模式
簡單工廠 height 判斷 目前 mes strong 產品 return logs 簡單工廠模式 簡單工廠模式是類的創建模式,又叫做靜態工廠方法模式。簡單工廠模式由一個工廠對象決定生產出哪一種產品類的實例。 為什麽要使用簡單工廠模式 原因很簡單:解耦。 LOL場
11設計模式六大原則——開閉原則
職責 art 並不是 錯誤 接口 屬於 倒置 編程 探討 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對整個功能進行重構,
《JAVA與模式》之簡單工廠模式
pue hgj ans vfs 創建對象 mdm gho fdm got 在閻宏博士的《JAVA與模式》一書中開頭是這樣描述簡單工廠模式的:簡單工廠模式是類的創建模式,又叫做靜態工廠方法(Static Factory Method)模式。簡單工廠模式是由一個工廠對象決定創建
一(1)簡單工廠模式
ner log factory auto 過多 測試 extend 耦合度 工廠 1 設計模式中經常用到程序設計中的封裝,繼承,多態的思想。不同的設計模式使代碼更加靈活,容易擴展。 2 設計模式中一般都會存在父類的概念,父類一般是抽象類,內部維護的變量,用於子類繼承;維護的
接口與簡單工廠模式
接口 簡單工廠模式 接口:使用interface關鍵字聲明接口。例如:接口需要被類實現,因為接口只做聲明不做實現。例如:Implements是實現接口關鍵字,一旦類實現了某個接口,就必須重寫這個接口聲明的方法。接口會有一個符號顯示著:看到這個符號就可以知道這是一個接口。聲明了接口就必須應用接口編程,不