工厂设计模式是一种常见的设计模式,用于创建对象,所以它是一种创建型模式。工厂模式有三种不同的变体:静态工厂、工厂方法、抽象工厂。使用工厂模式可以将创建对象的代码与使用对象的代码分离,这种解耦有助于提高代码的可维护性和可扩展性。在本博客中我们将通过一个订购冰淇淋的场景来说明工厂设计模式的优点
普通创建
我们使用UML来构建客户端订购冰淇淋的场景,父类( IceCream )冰淇淋维护了口味,以及制作方法,制作方法包括:搅拌、加热、添加材料、冰冻、打包,子类( ChocolateIceCream 、VanillaIceCream )通过重写 addMaterial 方法获取不同口味的冰淇淋。订购类( OrderIceCream )的 order 方法通过冰淇淋口味( taste )来选择创建香草味还是巧克力味的冰淇淋
现在我们同时支持香草味、巧克力味的冰淇淋订购了,并且我们使用了继承,如果要新增草莓味的冰淇淋,我们只需要新增一个继承父类的草莓冰淇淋类就可以了,扩展新产品非常简单
OCP 原则
按照上图的构建,我们来试试新增一种草莓冰淇淋会发生什么
我们很快的扩展了一款草莓冰淇淋,而使用方 OrderIceCream 同样需要修改代码来适应新款产品,如果使用方很多、冰淇淋种类不断增加,所有使用方都需要修改,这违反了 OCP 原则,更改的越多越容易出错,这种方式构建的订购冰淇淋系统扩展起来非常困难
OCP 即 Open-Closed Principle ,OCP 是面向对象设计中的一个基本原则,软件实体(类、模块、函数等)应该对提供方扩展开放,对使用方修改关闭
静态工厂
我们使用静态工厂来重新构建订购冰淇淋场景
当我们新增一款冰淇淋种类,只需要修改 IceCreamFactory 中的代码,而使用到 IceCreamFactory 的地方都无需修改。静态工厂将对象的创建与对象的使用逻辑解耦,提高了代码的可维护性、可扩展性,同时也符合 OCP 原则
DIP
在静态工厂模式构建的订购冰淇淋系统中,对于新增冰淇淋种类场景,系统提供了很好的维护性和扩展性。现在如果我们需要对冰淇淋产地进行分类,例如:土耳其香草冰淇淋,意大利巧克力冰淇淋等,系统应该如何扩展?我们可以继续使用静态工厂,针对不同产地的冰淇淋单独创建一个静态工厂,我们来试试看
由于使用方依赖了具体的工厂类,每新增一种冰淇淋工厂,客户端都需要更改代码以支持新的冰淇淋工厂,这违反了 OCP 原则,同时也违反了 DIP 原则
DIP 即 Dependency Inversion Principle ,DIP 是面向对象设计原则的一种,它强调高层模块不应该依赖低层模块,而是应该依赖于抽象接口(接口或抽象类)。同时,具体实现类应该依赖于抽象接口而不是高层模块。DIP 指导我们尽可能地使用抽象来编程,而不是具体的实现。这样可以使系统更加灵活、扩展性更好,同时也可以降低模块间的耦合度,提高代码的可维护性
工厂方法
我们可以使用工厂方法解决上面的问题,如下构建
基类工厂新增抽象方法 doCreate,子类实现真正的产品创建,解耦了具体工厂与使用方的依赖,符合 OCP 原则,同时也符合 DIP 原则
抽象工厂
抽象工厂提供了一个接口,用于创建一系列相关或依赖对象的家族,而不需要指定具体的类
这种方式同样符合 OCP 和 DIP 的设计原则
应用场景
工厂模式适用于创建复杂对象,控制对象创建过程。常见使用场景有
- 根据不同条件创建不同对象:如根据不同渠道创建不同的订单信息
- 创建的对象数量不确定时:如创建数据库、网络连接、线程等
People love what other people are passionate about. - Mia