通过简单工厂+反射+配置文件实现程序的可扩展
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);
}