通過簡單工廠+反射+配置文件實現程序的可擴展
1 通過簡單工廠模式實現面向接口編程
假設我們有一下幾個類代表遊戲用不用的角色
//繼承接口類
public class Human
{
//重寫接口類方法
public void ShowKing()
{
Console.WriteLine("The king of {0} is Sky", this.GetType().Name);
}
}
public class NE
{
public void ShowKing()
{
Console.WriteLine("The king of {0} is Blue", this.GetType().Name);
}
}
public class Player
{
public int id { set; get; }
public string name { set; get; }
}
其中Player是玩家,如果玩家需要使用Human這個遊戲角色, 需要給Player添加如下方法。
public void Play(Human role)
{
Console.WriteLine("{0} play games", this.name);
role.ShowKing();
}
若他想玩NE這個解釋,就還需要添加一個類似的方法。
public void Play(NErole)
{
Console.WriteLine("{0} play games", this.name);
role.ShowKing();
}
大家會不會覺得這樣的程序的擴展性太低,經常需要修改,弄有沒有辦法可以一勞永逸呢。沒錯,通過簡單工廠模式能在一定程度上解決這個問題。所謂簡單工廠,實現它的主要方式就是通過傳遞給工廠方法的參數,動態實例化一個對象,爲了實現這個功能,這些對象所屬德類必須繼承於一個公共父類,這樣採用用子類代替父類出現的地方。我們可以用定義一個父類來當做這個公共父類。
我們首先來定義這個接口,需要在這個接口中聲明一個子類都需要用到的方法。
//種族類都繼承於這接口
public interface IRace
{
//子類會重寫這個方法
//這樣在用子類代替父類時,會有自己獨特的行爲
void ShowKing();
}
接下來我們對遊戲角色
//繼承於接口後, 可以用子類賴替代父類出現的地方 並且可以使用子類自己的行爲
public class NE :IRace
{
public void ShowKing()
{
Console.WriteLine("The king of {0} is Sky", this.GetType().Name);
}
}
//繼承接口類
public class Human : IRace
{
//重寫接口類方法
public void ShowKing()
{
Console.WriteLine("The king of {0} is Sky", this.GetType().Name);
}
}
接下來在Play中玩家使用任何角色都可以用同樣的方法了
//將接口作爲參數可以使player面向抽象 依賴倒置
public void Play(IRace role)
{
Console.WriteLine("{0} play games", this.name);
role.ShowKing();
}
爲了方便通過傳入的參數來確定要實例化那個角色對象,我們可以使用一個工廠類來實現。
//種族類型的枚舉
public enum RaceType
{
Human,
NE,
ORC,
UnDead
}
public class ObjectFactory
{
//根據傳遞的種族類型動態地創建Irace的子類
public static IRace CreateRace(RaceType type)
{
IRace race = null;
switch (type)
{
case RaceType.Human:
race = new Human(); break;
case RaceType.NE:
race = new NE(); break;
default:
throw new Exception("wrong raceType");
}
return race;
}
}
然後在Main()方法中調用CreateRace()就能創建一個角色了。
IRace role= ObjectFactory.CreateRace(RaceType.Human);
Player player = new Player()
{
id = 1,
name = "LC"
};
player.Play(role);
自此時我們就實現了面向接口編程。
通過讀取配置文件中的內容來實例化遊戲角色
先在配置文件中添加要創建的角色對象的信息
<appSettings>
<add key="IRaceType" value="Human" />
</appSettings>
接下來,我們只需要在後臺獲取配置文件中的內容,然後根據它實例化對象就行了、
//根據配置文件中的內容來創建對象
private static string raceTypeConfig = ConfigurationManager.AppSettings["IRaceType"];
public static IRace CreateRaceByConfig()
{
RaceType type = (RaceType)Enum.Parse(typeof(RaceType), raceTypeConfig);
return CreateRace(type);
}
最後只需要在Mina()方法中調用CreateRaceByConfig()實例化角色就行了。
再加上反射實現可擴展
當我們想給一個項目添加一個新功能時,可以再新建一個項目,然後舊項目引用新項目的dll,最後再重新編譯一下老項目。其實這樣就很麻煩。還有一種方法就是把新項目的dll文件複製到老項目的bin\Debug下,然後在老項目中通過反射實例化出新項目中的對象。
先在配置文件中添加新項目中對象的信息。
<add key="IRaceTypeReflaction" value="SimpleFactoryServiceExtend,SimpleFactoryServiceExtend.FIve" />
value中的兩個值分別是dll的名稱和具體類的名稱
然後在工廠方法通過反射中實例化對象就行了
//根據讀取配置文件的內容通過反射創建文件
private static string configString = ConfigurationManager.AppSettings["IRaceTypeReflaction"];
private static string DllName = configString.Split(',')[0];
private static string ClassName = configString.Split(',')[1];
public static IRace CreateRaceByReflaction()
{
//加載指定dll
Assembly assembly = Assembly.Load(DllName);
//實例化dll中的一個對象
Type type = assembly.GetType(ClassName);
return (IRace)Activator.CreateInstance(type);
}