C#设计模式之工厂方法模式(Factory Method Pattern)

装饰模式解释: 

       工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

        工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合

模式类型: 创造类模式

使用时机:

1.对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。

2.只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的

在代理模式中的各个角色有:

抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。
抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应

UML图:


代码实现:

创建一个Operation类.

/// <summary>
/// 运算类
/// </summary>
class Operation
{
    private double _numberA = 0;
    private double _numberB = 0;
    public double NumberA
    {
        get { return _numberA; }
        set { _numberA = value; }
    }
    public double NumberB
    {
        get { return _numberB; }
        set { _numberB = value; }
    }

    /// <summary>
    /// 得到运算结果
    /// </summary>
    /// <returns></returns>
    public virtual double GetResult()
    {
        double result = 0;
        return result;
    }
}

依次创建OperationAdd,OperationSub,OperationMul,OperationDiv类.

/// <summary>
/// 加法类
/// </summary>
class OperationAdd : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = NumberA + NumberB;
        return result;
    }
}
/// <summary>
/// 减法类
/// </summary>
class OperationSub : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = NumberA - NumberB;
        return result;
    }
}
/// <summary>
/// 乘法类
/// </summary>
class OperationMul : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = NumberA * NumberB;
        return result;
    }
}
/// <summary>
/// 除法类
/// </summary>
class OperationDiv : Operation
{
    public override double GetResult()
    {
        double result = 0;
        if (NumberB == 0)
            throw new Exception("除数不能为0。");
        result = NumberA / NumberB;
        return result;
    }
}

创建工厂接口:IFactory.

/// <summary>
/// 工厂方法
/// </summary>
interface IFactory
{
    Operation CreateOperation();
}

依次创建具体的工厂类去实现接口.

/// <summary>
/// 专门负责生产“+”的工厂
/// </summary>
class AddFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationAdd();
    }
}
/// <summary>
/// 专门负责生产“-”的工厂
/// </summary>
class SubFactory : IFactory
{
    public Operation CreateOperation()
   {
        return new OperationSub();
    }
}
/// <summary>
/// 专门负责生产“*”的工厂
/// </summary>
class MulFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationMul();
    }
}
/// <summary>
/// 专门负责生产“/”的工厂
/// </summary>
class DivFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationDiv();
    }
}
客户端调用 .

Static void Main()
{
    IFactory operFactory = new AddFactory();
    Operation oper = operFactory.CreateOperation();
    oper.NumberA = 10;
    oper.NumberB = 20;
    double result = oper.GetResult();

    operFactory = new DivFactory();
    oper = operFactory.CreateOperation();
    oper.NumberA = 21;
    oper.NumberB = 7;
    result = oper.GetResult();
}

简单工厂 VS 工厂方法:

简单工厂的优点是工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对客户端来说,去除了与具体产品的依赖. (如计算器案例:客户端只要给"+"给工厂, 工厂就会生成相关的实例对象,客户端只要消费即可). 但是如果要增加新计算逻辑 "求平方".那就必须在工厂类里增加 Case 分支. 这就等于说我们不但对扩展开放了,也对修改(原的有类)开放了.违背了开放-封闭原则.

工厂方法则是在简单工厂的基础上把工厂类抽象出一个接口,并且这个接口只有一个方法,就是创建抽象产品的工厂方法. 然后所有要生产具体类的工厂,就去实现这个接口.于是如果要增加 "求平方"功能时,就不需要改原有的工厂类, 只需要增加此功能的 运算类 和相应的 工厂类 就可以了. 这样就实现了对扩展开放,对修改封闭. 符合开放-封闭原则.

工厂方法的缺点:

工厂方法把简单工厂内部的逻辑判断移到了客户端来进行, 新增功能时变成要修改客户端. 要解决这个问题,可以使用 "反射" .

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值