读书笔记-设计模式-可复用版-简单工厂VS工厂方法

在设计模式可复用版中,并没有提到简单工厂,我是在大话设计模式中看到这个说法

实际上,简单工厂在工厂方法(Factory Method)一章节中,叫做参数化的工厂方法,接受一个标识对象种类的参数,使得工厂方法可以创建多种产品。

“工厂“即是用于"生产”产品的,简单工厂是通过一个统一的接口,通常是静态的,接受一个对象种类的参数,通过if else或是switch case 条件判断,返回不同种类的对象。

工厂方法(Factory Method) 概念:

定义一个用于创建对象的接口,让子类决定,实例化哪一个类。Factory Method 使一个类的实例化,延迟到子类。

在大话设计模式中,通过采用计算器,+、-、*、/等不同的运算,来应用工厂方法,也是不错的例子,我这里稍后会采用一个"货币兑换”来进行阐述工厂方法(Factory Method)的使用,但先还原一下运算器的例子吧

public class Operation

  public float num1 { get; set; }

  public float num2 { get; set; }

  public virtual float GetResult() { return 0; }

public class Add : Operation

  public override float GetResult()

  {

    return num1 + num2;

  }

public class Sub : Operation

  public override float GetResult()

  {

    return num1 - num2;

  }

public class Mul : Operation

  public override float GetResult()

  {

    return num1 * num2;

  }

public class Div : Operation

  public override float GetResult()

  {

    if (num2 == 0)

    {

      Debug.LogError("num2 is zero!");

      return 0;

    }

    return num1 / num2;

  }

public class OperationFactory

  public static Operation CreateOperation(string type)

  {

    Operation operation = null;

    switch (type)

    {

      case "+":

        operation = new Add();

        break;

      case "-":

        operation = new Sub();

        break;

      case "*":

        operation = new Mul();

        break;

      case "/":

        operation = new Div();

        break;

    }

    return operation;

  }

测试代码:

Operation operation = OperationFactory.CreateOperation("*");

operation.num1 = 10;

operation.num2 = 10;

Debug.Log(operation.GetResult());

所有的运算符派生成基类Operation(Product) ,并通过OperationFactory参数化工厂方法,根据type,返回指定的运算符对象。

但上面的代码有个弊端,如果我新增一个运算符,我就需要修改一次OperationFactory,

加一个case或是if else,这样也可能会影响其它代码,但你新增一个二手手机号码拍卖运算符或是对某一个运算符做修改,影响到其它已经稳定在使用中的运算符,显然是不合理的,这其实违背了开放-封闭原则,设计模式一共有6大原则,这会在后面着重介绍

所以,我们需要解决这种情况,基于接口的的工厂方法可以消除switch case 或if else,从而

新增或是修改运算符,不影响其它部分。

添加一个IOperation接口,接口只提供了一个CreateOperation工厂方法,用于创建运算符:

public interface IOperation{

 Operation CreateOperation();

并分别新建四个运算符类,实现IOperation接口:

public class AddOperation : IOperation

  public Operation CreateOperation()

  {

    return new Add();

  }

public class SubOperation : IOperation

  public Operation CreateOperation()

  {

    return new Sub();

  }

public class MulOperation : IOperation

  public Operation CreateOperation()

  {

    return new Mul();

  }

public class DivOperation : IOperation

  public Operation CreateOperation()

  {

    return new Div();

  }

测试代码:

IOperation operation = new AddOperation();

Operation op = operation.CreateOperation();

op.num1 = 10;

op.num2 = 5;

Debug.Log(op.GetResult());

通过修改,已经消除了switch case / if else带来的弊端,我新增一个运算符,或是修改已有的运算符,对其它运算符都不会有影响,而且也不需要单独的构建一个OperationFactory类,结构要比参数化工厂方法更好

但工厂方法也是有缺点的,比如我新增一个运算后,我就需要新增一个实现IOperation接口的工厂类,用于创建具体的产品(Product),但我个人并不认为这是什么大的缺点,有必要的时候是一定要添加的,但要解决也是有办法的

我们看上面实现了IOperation接口的这些工厂类:

AddOperation

SubOperation

MulOperation

DivOperation

除了名字,所有的实现都是相同的,这里就可以使用泛型或模板,来减少重复的代码,提高代码的重用性

只需要定义一个泛型类:

public class OperationGeneric<T> : IOperation where T : Operation, new()

  public Operation CreateOperation()

  {

    return new T();

  }

测试代码:

IOperation operation = new OperationGeneric<Mul>();

Operation op = operation.CreateOperation();

op.num1 = 10;

op.num2 = 5;

Debug.Log(op.GetResult());

IOperation operation = new OperationGeneric<Mul>();

需要什么运算符,只需要在<>中指定即中。

这样,上面新增的:

AddOperation

SubOperation

MulOperation

DivOperation

就全部可以删除掉了,新增的运算符,也不需要再新增一个实现IOperation的工厂类了。

使用模板,可以避免创建子类。

还有一点需要提到,之前在Singleton章节讲到过,Lazy Initalization 懒汉式或是延迟初始化,只有在使用的时候,如果不存在,我才会去创建

工厂方法,目前就是采用的Lazy Initalization.

再贴下结构图:

Product 产品的基类,我们通常要派生实现,因为尽量的避免面向具体的类(ConcreteClass)编程,要面向抽象编程。

ConcreteProduct 派生自Product

在上面的例子中,Operation是Product,是基类

Add,Sub,Mul,Div分别派生自Operation基类,他们是ConcreteProduct

Creator 是工厂方法的接口

ConcreteCreator是实现了Creator接口的具体工厂类,创建不同运算符的类。

AddOperation,SubOperation...这些(但我们通过泛型来避免创建更多的子类,不要忘记这一点)

在抽象工厂Abstract Factory中,经常用工厂方法Factory Method来实现,下一章,我们会来介绍创建型的最后一个设计模式,抽象工厂Abstract Factory.

最后,提供货币兑换的例子,以巩固工厂方法(Factory Method)的练习 :

假设,我现在有100块钱人民币,我想要兑换成美元,英镑,欧元和卢布,如何通过工厂方法来实现?

这里的美元,英镑,欧元和卢布,就是我们Product,我们先需要定义一个基类Product,这是为了避免向面具体的产品(ConcreteProduct)进行编程,将公共的接口抽象出来。然后创建相应的子类派生实现它。

public class Exchange

  public float amount{get;set;}//现金数

  public virtual float Translation() { return 0; }//返回兑换数

public class USDExchange : Exchange

  public override float Translation()

  {

    return amount * 0.1490f;

  }

public class GBPExchange : Exchange

  public override float Translation()

  {

    return amount * 0.1131f;

  }

public class EURExchange : Exchange

  public override float Translation()

  {

    return amount * 0.1318f;

  }

public class RUBExchange : Exchange

  public override float Translation()

  {

    return amount * 9.8227f;

  }

下面定义工厂方法的接口:

public interface IExchange

  Exchange CreateExchange();

为了避免创建子类,我们使用泛型:

public class ExchangeGeneric<T> : IExchange where T : Exchange, new()

  public Exchange CreateExchange()

  {

    return new T();

  }

测试代码:

IExchange exchangeFactory = new ExchangeGeneric<RUBExchange>();

Exchange exchange = exchangeFactory.CreateExchange();

exchange.amount = 100;

Debug.Log("amount:"+exchange.Translation());

输出结果:

amount:982.27

(我对俄罗斯是有情怀的:)

工厂方法就介绍到这里,接下来会介绍抽象工厂Abstract Factory的使用,然后会对创建型的五种设计模式,做一次总结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值