工厂模式
简单工厂模式
定义:由一个工厂对象决定创建出哪一种类型实例。客户端只需传入工厂类的参数,无心关心创建过程。
优点:具体产品从客户端代码中抽离出来,解耦。
缺点:工厂类职责过重,增加新的类型时,得修改工程类得代码,违背开闭原则。
举例:新建Fruit水果抽象类,包含eat抽象方法:
1 | public abstract class Fruit { |
其实现类Apple:
1 | public class Apple extends Fruit{ |
新建创建Fruit的工厂类:
1 | public class FruitFactory { |
新建个客户端测试一下:
1 | public class Application { |
运行main方法,输出:
1 | 吃🍎 |
可以看到,客户端Application并未依赖具体的水果类型,只关心FruitFactory
的入参,这就是客户端和具体产品解耦的体现,UML图如下:
工厂方法模式
为了解决简单工厂模式的缺点,诞生了工厂方法模式(Factory method pattern)。
定义:定义创建对象的接口,让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到了子类进行。
优点:
- 具体产品从客户端代码中抽离出来,解耦。
- 加入新的类型时,只需添加新的工厂方法(无需修改旧的工厂方法代码),符合开闭原则。
缺点:类的个数容易过多,增加复杂度。
举例:新建Fruit抽象类,包含eat抽象方法:
1 | public abstract class Fruit { |
新建FruitFactory
抽象工厂,定义produceFruit
抽象方法:
1 | public abstract class FruitFactory { |
新建Fruit的实现类,Apple:
1 | public class Apple extends Fruit { |
新建FruitFactory
的实现类AppleFruitFactory
,用于生产具体类型的水果 —— 苹果:
1 | public class AppleFruitFactory extends FruitFactory{ |
新建客户端Application测试一波:
1 | public class Application { |
运行main方法,输出如下:
1 | 吃🍎 |
现在要新增Banana类型的水果,只需要新增Banana类型的工厂类即可,无需修改现有的AppleFruitFactory
代码,符合开闭原则。但是这种模式的缺点也显而易见,就是类的个数容易过多,增加复杂度。
上面例子UML图如下所示:
抽象工厂模式
抽象工厂模式(Abstract factory pattern)提供了一系列相关或者相互依赖的对象的接口,关键字是“一系列”。
优点:
- 具体产品从客户端代码中抽离出来,解耦。
- 将一个系列的产品族统一到一起创建。
缺点:拓展新的功能困难,需要修改抽象工厂的接口;
综上所述,抽象工厂模式适合那些功能相对固定的产品族的创建。
举例:新建水果抽象类Fruit,包含buy抽象方法:
1 | public abstract class Fruit { |
新建价格抽象类Price,包含pay抽象方法:
1 | public abstract class Price { |
新建水果创建工厂接口FruitFactory
,包含获取水果和价格抽象方法(产品族的体现是,一组产品包含水果和对应的价格):
1 | public interface FruitFactory { |
接下来开始创建🍎这个“产品族”。新建Fruit实现类AppleFruit:
1 | public class AppleFruit extends Fruit{ |
新建对应的苹果价格实现ApplePrice
:
1 | public class ApplePrice extends Price{ |
创建客户端Application,测试一波:
1 | public class Application { |
输出如下:
1 | 购买🍎 |
客户端只需要通过创建AppleFruitFactory
就可以获得苹果这个产品族的所有内容,包括苹果对象,苹果价格。要新建🍌的产品族,只需要实现FruitFactory
、Price和Fruit接口即可。这种模式的缺点和工厂方法差不多,就是类的个数容易过多,增加复杂度。
上面例子UML图如下所示:
参考资料:
https://snailclimb.gitee.io/javaguide/#/docs/system-design/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F
https://mrbird.cc/Java%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.html