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

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

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

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

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

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

 

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

程序需求:

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

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
    }
}

工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
    }
}

 

客户端调用:

1
2
3
4
5
6
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 @   赵学智  阅读(4242)  评论(4编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示