技术开发 频道

Simple Factory和Reflection

 【IT168技术文档】在这篇文章中,引入Reflection来实现Simple Factory,增强系统的可扩展性。

 下面是Reflection在msdn的定义

 Reflection provides objects (of type Type) that describe assemblies, modules and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties.

 我的理解是Reflection在运行时提供从assemblies(.NET平台下编译生成的DLL或者EXE文件)取出Metadata信息的功能,然后可以对Metadata的信息进行读取,修改,以及动态的根据这些Metadata生成对象。

 由于.NET平台提供Reflection,意味着.NET开发的assemblies很容易就可以进行disassemble(反编译),同时也可以通过Reflection调用一下非public的Methods,但是这些不是这篇文章讨论的范围。

 现在先看回上篇文章中Simple Factory的实现。

 

  public enum GameDiskType

 {

 Racing,

 Shooting,

 Fighting

 }

 public sealed class PS3DiskFactory

 {

 public static AbstractGameDisk CreateGameDisk(GameDiskType type)

 {

 switch (type)

 {

 case GameDiskType.Racing:

 return new PS3RacingGameDisk();

 case GameDiskType.Shooting:

 return new PS3ShootingGameDisk();

 case GameDiskType.Fighting:

 return new PS3FightingGameDisk();

 default:

 return null;

 }

 }

 }

 为了方便演示Reflection,我把GameDiskType的定义修改了一下,区分大小写。从原先没有使用模式,直接在Client new对象的方式到使用Simple Factory,实现了对对象实例化过程的封装,所有的对象实例化变化被封装到PS3DiskFactory的工厂类里面了。这一步符合设计原则“封装变化”。可是有人会问,在PS3DiskFactory里面,如果新增GameDisk还是需要修改条件从句(switch...case),和原先的设计没有太大的改变,从Refactoring的角度看,代码还是有臭味道。 Well,Well,Well,你的鼻子真灵呀。这里涉及到设计上的边界(Boundary)问题。从Client类看,PS3DiskFactory确实把对象初始化的需求封装了,变化不会在Client类里面发生。从整个系统来看,对象初始化的变化,还是需要修改源代码(例如修改PS3DiskFactory),那怎么解决这个问题了,在.NET里面提供了Reflection可以解决这个问题。

 

  public sealed class PS3DiskFactory

 {

 public AbstractGameDisk CreateGameDisk(GameDiskType type)

 {

 // Get fully qualified factory name

 string name = this.GetType().Namespace + ".PS3" + type.ToString() + "GameDisk";

 // Dynamic factory creation

 return System.Activator.CreateInstance(Type.GetType(name)) as AbstractGameDisk;

 }

 }

 在CreateGameDisk里面,先组成需要实例化的类的全名称(fully qualified name),然后使用System.Activator.CreateInstance来生成。上面是PS3DiskFactory的代码,用于实例化PS3的GameDisk,可以看到生成全名称的时候hard code了”PS3“。如果把设备名字作为参数传递到工厂中,那么一个工厂就可以同时生成PS3和Wii的GameDisk了。

 

  public enum GameDevice

 {

 PS3,

 Wii

 }

 public sealed class DiskFactory

 {

 public AbstractGameDisk CreateGameDisk(GameDevice device, GameDiskType type)

 {

 // Get fully qualified factory name

 string name = this.GetType().Namespace + "." + device.ToString() + type.ToString() + "GameDisk";

 // Dynamic factory creation

 return System.Activator.CreateInstance(Type.GetType(name)) as AbstractGameDisk;

 }

 }

0
相关文章