代码改变世界

《深入浅出设计模式-中文版》读书笔记-工厂模式(五)

2010-07-16 12:46  Virus-BeautyCode  阅读(3083)  评论(9编辑  收藏  举报

  今天给大家带来的是:工厂模式。

  我们在代码中创建一个对象,我们会很自然的想到new。其实,除了new意外,我们还有很多的方式可以创建对象。不说复杂的模式,就说简单的语法,其实.NET框架中还有下面的方法。根据需要创建的对象的类型,动态创建对象。

  

Activator.CreateInstance

 

  通过前面我们已经讲过一条原则:

  针对接口编程,不针对实现编程。

  使用new创建对象很明显就是一个针对实现编程,new后面需要一个具体的类,不允许你new一个接口或者是抽象类。包括用Activator.CreateInstance都不能创建接口或者抽象类。

  那是不是就是说以后不能或者是不要再用new了,都用其他方式吗?

  也不是的,也要根据情况来分析,不是一概而论的,在后面会给出一些简单的标准,更多的要结合具体的设计定夺。

  很多时候我们会碰到下面的代码:

  

代码
     string userType = "";
                
if (userType == "admin")
                {
//创建管理员
                }
                
else if (userType == "supervisor")
                {
//创建超级管理员
                }
                
else if (userType == "coommon")
                {
                    
//创建普通用户
                }

 

  如果以后增加了用户的类型,不仅要创建用户类型实体,还需要打开创建用户的这段代码,后面加上一个if。。。else。。。。

  如果这段代码没有封装,就更麻烦了,散落在项目的各处,每个地方都要打开,ctrl+c,ctrl+v。开始了无尽的噩梦。

  对于后面的维护成了问题,而且违反了一条原则:

   

  OCP原则,对增加开放,对修改封闭。

  首先使用封装变化原则对这段代码做一些抽象,上面这段明显是变化较多的地方,其他的代码可能是现实创建的用户的姓名之类的。变成一个方法,然后将用户类型定义为enum类型,减少调用者由于输入错误导致程序错误。

  

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BeautyCode.DesignPattern.Head.First.Factory
{
    
public enum UserType
    {
        Admin,
        Supervisor,
        Common
    }
    
public abstract class User
    {
        
public virtual UserType UserType
        {
            
get;
            
protected set;
        }
        
public User(UserType userType)
        {
            UserType 
= userType;
        }
        
public virtual string Username
        {
            
get;
            
set;
        }
        
public virtual int Age
        {
            
get;
            
set;
        }
        
public virtual void DisplayName()
        {
            Console.WriteLine(
"my name is {0}, i'm {1} years old.", Username, Age);
        }
    }
    
public class AdminUser : User
    {
        
public AdminUser()
            : 
base(UserType.Admin)
        { }
    }
    
public class CommonUser : User
    {
        
public CommonUser()
            : 
base(UserType.Common)
        { }
    }
    
public class SupervisorUser : User
    {
        
public SupervisorUser()
            : 
base(UserType.Supervisor)
        {
        }
    }
}

 

  

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BeautyCode.DesignPattern.Head.First.Factory
{
   
public  class UserFactory
    {
       
public static User CreateSingleUser(UserType userType)
       {
           User user 
= null;
           
switch (userType)
           {
               
case UserType.Admin :
                   user 
= new AdminUser(); 
                   
break;
               
case UserType.Common :
                   user 
= new CommonUser();
                   
break;
               
case  UserType.Supervisor :
                   user 
= new SupervisorUser();
                   
break;
               
default :
                   
break;
           }
           
return user;
       }
    }
}

 

  调用代码

 

Head.First.Factory.User user = Head.First.Factory.UserFactory.CreateSingleUser(Head.First.Factory.UserType.Admin);

 

  以后增加新的用户类型就不用在各处修改了,只要新建一个类型实体,然后打开工厂方法,修改一下就可以了。

  有没有更好的呢?

  能否只是增加一个用户类型实体类呢?

  答案是:能

 

  修改一下工厂方法,利用泛型和Activator

  

 public static T CreateSingleUser2<T>() where T:User
       {
           T user 
= null;
           user 
= Activator.CreateInstance<T>();
           
return user;
       }

 

  调用者的代码修改为

  

 Head.First.Factory.User user1 = Head.First.Factory.UserFactory.CreateSingleUser2<Head.First.Factory.AdminUser>();

 

  有没有更好的呢?

  期待大家的参与讨论!!!!

  其实我这个还不算是真正意义上的工厂模式,顶多算是个简单的工厂,后面我会补充一些更好的例子。

  感谢大家耐心看完本篇博文。

  定义

  工厂模式:定义了一个创建对象的借口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到了子类。

   上面的描述中提到了“子类决定”的决定,希望不要错误理解,不是模式允许子类本身在运行的时候做决定,而是指在编写创建者类的时候,不需要知道实际创建的类是哪一个。调用者选择使用哪个类,自然就决定了实际创建的对象。