舞步者

带她一起去周游世界
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

设计模式之三FactoryMethod模式

Posted on 2008-05-23 15:43  Kevin_Zhang  阅读(179)  评论(0)    收藏  举报

先看简单例子的一个逐步的演化过程:
有这样的需求:根据不同类型的员工,计算其薪水(类型不同,薪水的计算方式不同);那么我们有这样的初期代码:

 public class Calculate
    
{
        
public void CalEngineer()
        

        
        }

        
public void CalCleaner()
        

        
        }

        
public void CalHr()
        

            
        }

        
public void Calculate()
        
{
            
switch (Employee.Type)
            

                
case "Engineer":
                    CalEngineer();
                    
break;
                
case "CalCleaner":
                    CalCleaner();
                    
break;
                
case "CalHr()":
                    CalHr();
                    
break;
                
default:
                    
break;
            }

        }

    }
将来,如果又要一种新的员工类型,比如说销售员工,那么我们就需要更改这个类:添加一个计算销售类型薪水的函数,再添加一个Case类型,调用销售薪水计算函数;也就是说我们的Calculate这个类会经常的改变,我们的程序也应此要不断的改变。
再仔细看这个问题,我们发现这些不同类型的员工之间并没有直接的联系,可以作为不同的员工类处理
 public  class Engineer
    
{
        
public void CalculateSalary()
        
{ }
    }

    
public class Cleaner
    
{
        
public void CalculateSalary()
        
{ }
    }

    
public class Hr
    
{
        
public void CalculateSalary()
        
{ }
    }
但是如果细想一下我们的客户代码,也许会出现这样的代码:
Engineer engineer=new Engineer();
engineer.CalculateSalary();
那么,如果我们的员工类型变成其他类型,那么我们的代码中出现这种代码的地方都要改,也就说我们要进行解耦处理,那么我们可以进一步的抽象:
 public abstract class Employee
    
{
        
public abstract void CalculateSalary();
    }

    
public class Engineer : Employee
    
{
        
public override void CalculateSalary()
        
{
            
        }

    }

    
public class Cleaner : Employee
    
{
        
public override void CalculateSalary()
        
{

        }

    }

    
public class Hr : Employee
    
{
        
public override void CalculateSalary()
        
{

        }

    }
在这里,我们再回头看看我们客户代码的调用中紧耦的问题并没有得到解决,那么这个时候我们就应该用到工厂模式了
概述:
在软件系统中,经常面临某个对象的创建工作,但是由于需求的变化,这个对象的具体实现经常面临剧烈的变化,但是它却有稳定的接口。
意图:
定义一个用户创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
我们的问题可以对照概述:我们要创建一个员工的对象,但此对象计算薪水的方式却经常由于类型不同而剧烈变化,但是不管是哪种类型,他们都需要计算薪水
我们根据意图进行解决:创建一个接口(抽象类),以及其子类;让子类去决定该实例化具体化的那种类型;也就是每个子类要对应具体的一个类型,在子类内实例化具体的员工类型。那么我们的程序如下:
 public abstract class EmployeeFactory
    
{
        
public abstract Employee Create();
    }

    
public class EngineerFactory : EmployeeFactory
    
{
        
public override Employee Create()
        
{
            
return new Engineer();
        }

    }

    
public class CleanerFactory : EmployeeFactory
    
{
        
public override Employee Create()
        
{
            
return new Cleaner();
        }

    }

    
public class HrFactory : EmployeeFactory
    
{
        
public override Employee Create()
        
{
            
return new Hr();
        }

    }
我们再来看我们的客户程序调用代码:
 EmployeeFactory fac = new EngineerFactory();
 Employee emp=fac.Create();
 emp.CalculateSalary();
除了第一句等号以来了具体实现外,其他地方都没依赖具体的实现,依赖的是高层的接口;需求来的时候,我们只要将改掉即可,比如:
EmployeeFactory fac = new HrFactory();
而其他的地方都不要再改
那么,对于第一句所出现的问题,我们可以通过配置文件的方式和使用反射进行解决,这样,源程序都不需要再改了
配置文件有如下节:
<appSettings>
2    <add key="factoryName" value="EngineerFactory"></add>
3</appSettings>
我们的客户程序代码:
string factoryName = ConfigurationSettings.AppSettings["factoryName"].ToString();
  EmployeeFactory fac 
= (EmployeeFactory)Assembly.Load("FactoryMethod2").CreateInstance("FactoryMethod2." + factoryName);//创建实例
  Employee emp = fac.Create();
  emp.CalculateSalary();
根据上述,我们发现,工厂类和产品类是一一对应的关系,将来在出现新的产品类型时,我们只要添加这个产品类,让其继承于抽象产品类;添加一个具体工厂类,让
其继承抽象工厂类即可。