设计模式培训之二:简单工厂、工厂方法

查看本人文章索引请通过http://www.cnblogs.com/seesea125/archive/2012/04/17/2453256.html

一、简单工厂和工厂方法定义:

简单工厂模式是由一个工厂类根据参数来决定创立出哪一种产品类的实例。

工厂方法模式通过调用不同的方法返回需要的类,而不是去实例化具体的类。 对实例创建进行了包装。 工厂方法是一组方法, 他们针对不同条件返回不同的类实例,这些类一般有共同的父类。

工厂方法模式实施一种按需分配的策略, 即传入参数进行选择, 工厂方法根据参数进行选择,返回具体的实例。

 

二、实例讲解:实现加减乘除

程序需求:

处理两个数的+,-,*,/等运算

 

1. 是面向过程的实现方法:

string strResult = "";
            switch (Operate)
            {
                case "+":
                    strResult = Convert.toString(Convert.ToDouble(NumA) + Convert.ToDouble(NumB));
                    break;
                case "-":
                    strResult = Convert.toString(Convert.ToDouble(NumA) - Convert.ToDouble(NumB));
                    break;
                case "*":
                    strResult = Convert.toString(Convert.ToDouble(NumA) * Convert.ToDouble(NumB));
                    break;
                case "/":
                    if (NumB != 0)
                    {
                        strResult = Convert.toString(Convert.ToDouble(NumA) + Convert.ToDouble(NumB));
                    }
                    else
                    {
                        strResult = "除数不能为0";
                    }
                    break;
            }

当增加需求时,例如:增加开方运算,这时我们需要更改上面switch的代码。如果再增加需求,还要更改switch代码。这样的代码很难维护。

健壮的设计应该是易扩展,不修改原有代码(或尽量减少修改原有代码)。

应对变化的运算方式,简单工厂就是一个很简单,好用的模式,下面是简单工厂的实现

 

2. 用简单工厂实现:

ULM图:

sclip_image002

public abstract class Operation
{
    public double NumA { get; set; }
    public double NumB { get; set; }
    public abstract double GetResult();
}

public class OperationAdd : Operation
{
    public override double GetResult()
    {
        return NumA + NumB;
    }
}

public class OperationSub : Operation
{
    public override double GetResult()
    {
        return NumA - NumB;
    }
}

工厂类:

public class Factory
{
    public Operation Create(string ope)
    {
        Operation operation=null;
        switch(ope)
        {
        case "+":
        operation=new OperationAdd();
        break;
        case "-":
        operation=new OperationSub();
        break;
        }
        return operation;
    }
}

 

客户端调用:

Operation oper;

oper=new Factory().Create("+");
oper.NumA=1;
oper.NumB=2;
double result=oper.GetResult();

这时在客户端代码就没有switch代码,现在的switch代码也没有运算逻辑。运算逻辑在GetResult()方法中。

当再有新需求时,我就可以增加子类(继承自Operation),在子类的GetResult方法中设置运算规则。现在只需在switch中增加一个case返回增加子类实例的代码。

简单工厂是一个不完美的模式,因为它还是修改了switch代码。

 

3 用工厂方法实现:

应对上面的需求也可以使用工厂方法模式,工厂方法使一个类的实例化延迟到其子类。

UML图:

clip_image004

    public interface IFactory
    {
        Operation Create();
    }
    public class AddOperation : IFactory
    {
        public Operation Create()
        {
            return new OperationAdd();
        }
    }
    public class SubOperation : IFactory
    {
        public Operation Create()
        {
            return new OperationSub();
        }
    }

    public abstract class Operation
    {
        public double NumA { get; set; }
        public double NumB { get; set; }
        public abstract double GetResult();
    }
    public class OperationAdd : Operation
    {
        public override double GetResult()
        {
            return NumA + NumB;
        }
    }
    public class OperationSub : Operation
    {
        public override double GetResult()
        {
            return NumA - NumB;
        }
    }

 

客户端:

IFactory factory = new AddOperation();
Operation oper = factory.Create();
oper.NumA = 3;
oper.NumB = 2;
double result = oper.GetResult();

 

在客户程序中,我们有效地避免了具体产品对象和应用程序之间的耦合,可是我们也看到,增加了具体工厂对象和应用程序之间的耦合。

当我们由加号操作变成减号操作时,只需要改动一处就可以了,其他地方都不用改。

IFactory factory = new SubOperation();
Operation oper = factory.Create();
oper.NumA = 3;
oper.NumB = 2;
double result = oper.GetResult();

 

当然这样的话,我们还是改动代码,这时候可以利用.NET反射机制来消除它,这样改动时,只需要改动配置文件就可以了

<appSettings>
  <add key="factoryName" value="AddOperation"></add>
</appSettings>

客户端代码:

string factoryName = ConfigurationSettings.AppSettings["factoryName"];
 IFactory factory = (IFactory)Assembly.Load("BLL").CreateInstance("BLL." + factoryName);
Operation oper = factory.Create();
oper.NumA = 3;
oper.NumB = 2;
double result = oper.GetResult();


 

posted @ 2012-05-02 14:16  赵学智  阅读(4238)  评论(4编辑  收藏  举报