我的实用设计模式 - Simple Factory和Reflection

简介:

更新1:使用as转换数据类型。

 

在上篇文章 我的实用设计模式 - Simple Factory,Factory Method和Abstract Factory 讲述了Simple Factory,Factory Method和Abstract Factory的关系以及演变过程。在这篇文章中,引入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 ;
    }
}
复制代码

 

在上述代码中,要实例化的对象的namespace是和当前工厂类是同一个namespace,同样要实例化的类和工厂类在同一个Assembly里面。当然他们可以分布于不同的assemblies。拿上篇文章的Asbtract Factory的工厂类作为例子,如果不同的游戏机类型,其Concrete Factories和Concrete Products分别独立存在于一个namespace和assembly,例如

复制代码
namespace  PS3
{
    
public   class  PS3Console : AbstractGameConsole
    {
    }

    
public   class  PS3Joystick : AbstractJoystick
    {
    }
    
    
public   class  PS3Player : AbstractPlayer
    {
        
public   override  AbstractGameDisk CreateGameDisk(GameDiskType type)
        {
            
return   new  PS3RacingGameDisk();
        }

        
public   override  AbstractGameConsole CreateGameConsole()
        {
            
return   new  PS3Console();
        }
        
public   override  AbstractJoystick CreateJoystick()
        {
            
return   new  PS3Joystick();
        }
    }
}
复制代码

 

名字空间(namespace)为PS3的程序编译到PS3Factory.dll中,而Wii的实现在WiiFactory.dll中,以下是原有没有使用Reflection的实现。

复制代码
public   enum  GameDevice
{
    PS3,
    Wii
}

public   class  Player
{
    
private  AbstractPlayer playerFactory;

    
public  Player(GameDevice device)
    {
        
switch  (device)
        {
            
case  GameDevice.PS3:
                playerFactory 
=   new  PS3Player();
                
break ;
            
case  GameDevice.Wii:
                playerFactory 
=   new  WiiPlayer();
                
break ;
        }
    }
}
复制代码

 使用Reflection后,可以把switch去掉,代码如下:

复制代码
public   class  Player
{
    
private  AbstractPlayer playerFactory;
    
public  Player(GameDevice device)
    {
        
// Load Assembly
        Assembly asm  =  Assembly.LoadFrom(device.ToString()  +   " Factory.dll " );

        
//  Get fully qualified factory name
         string  name  =  device.ToString()  +   " . "   +  device.ToString()  +   " Player " ;
        
//  Dynamic factory creation
        playerFactory  =  asm.CreateInstance(name) as  AbstractPlayer ;
    }
}
复制代码

 

GameDevice可以来自于配置文件。使用Reflection后,系统动态plug-in新的模块,例如需要增加Xbox模块,把Xbox的Concrete Factories和Concrete Products实现封装到Xbox的namespace,同时编译到XboxFactory.dll,修改GameDevice的配置文件就可以了。

参考文献:

Reflection (C# Programming Guide)



    本文转自Jake Lin博客园博客,原文链接:http://www.cnblogs.com/procoder/archive/2009/04/30/1447024.html,如需转载请自行联系原作者



相关文章
|
7月前
|
设计模式 Java
【设计模式】JAVA Design Patterns——Abstract Factory(抽象工厂模式)
【设计模式】JAVA Design Patterns——Abstract Factory(抽象工厂模式)
|
3月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
7月前
|
设计模式
设计模式之工厂 Factory
设计模式之工厂 Factory
57 1
|
7月前
|
设计模式
设计模式(二)工厂方法模式(Factory Method)
设计模式(二)工厂方法模式(Factory Method)
37 0
|
设计模式 Java 程序员
认真学习设计模式之工厂模式(Factory Pattern)
认真学习设计模式之工厂模式(Factory Pattern)
67 0
|
设计模式 Java
设计模式6 - 抽象工厂模式【Abstract Factory Pattern】
设计模式6 - 抽象工厂模式【Abstract Factory Pattern】
38 0
|
设计模式
设计模式5 - 工厂方法模式【Factory Method Pattern】
设计模式5 - 工厂方法模式【Factory Method Pattern】
35 0
|
设计模式 Java 程序员
【设计模式——学习笔记(下)】23种设计模式——工厂模式Factory(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——工厂模式Factory(原理讲解+应用场景介绍+案例介绍+Java代码实现)
63 0
|
设计模式 Java 关系型数据库
【设计模式——学习笔记(上)】23种设计模式——工厂模式Factory(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——工厂模式Factory(原理讲解+应用场景介绍+案例介绍+Java代码实现)
81 0
|
设计模式
【3W2H设计模式】抽象工厂模式(Abstract Factory Pattern)
【3W2H设计模式】抽象工厂模式(Abstract Factory Pattern)
149 0