写在前面:关于设计模式,B站上有很多讲解视频,相关的博客也有不少。本篇博客是在看完B站上的视频讲解后,并查阅了许多相关博客后,进行的总结
学习时看了B站视频:一周带你彻底弄懂23种设计模式 图灵学院
设计模式的运用无非是解决以下几个问题:
- 扩展性
- 健壮性
- 降低耦合
- 增强内聚
当知道以上本质的时候,在学习或者使用设计模式的时候,经常要思考:
- 不用的话,又将带来什么麻烦呢?
- 用了这个设计模式,将带来什么样的好处?
- 如果不用,后续带来的【麻烦成本】是否可以承受(从个人和团队角度)?
当想清楚以上三个问题的后,我们将可能减少设计模式的滥用,降低陷入「过度设计」的概率。
一、概述
工厂方法(Factory Method)设计模式:定义一个用于创建对象的接口,让子类绝定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
工厂方法模式的优点:
- 良好的封装性,代码结构清晰。
- 扩展性非常优秀,符合开闭原则。在增加产品类的情况系下,只有适当的修改具体的工厂类或扩展一个工厂类,就可以“拥抱变化”。
- 屏蔽产品类。产品类的实现如何变化,调用者无需关心,它只需关心产品的接口,只要接口保持不变,系统中的上层模块就不需要发生变化。
- 解耦框架。高层模块只需要知道产品的抽象类,其他实现类都不用关心。
二、完成一个小需求
现在有一个需求,需要我创建一个产品 ProductA,这个需求简单,我很快就写完了:
class ProductA {
public void function() {
System.out.println("ProductA do something...");
}
}
当别人相要使用我创建的 ProductA
时,直接 new ProductA()
即可。这时,就要考虑一个问题,如果以后我的 ProductA
构建方式有变,因为构建ProductA
的过程散落在系统的各个角落,则要改多个地方。当需要用改这个字时,就已经违反了**扩展性原则
**(开闭原则)。
因此,我将对象定义方式
和对象创建方式
分离,解耦,即把对象的创建方式放到一个工厂类中Factory
:
public class Factory {
public ProductA createProduct() {
ProductA productA = new ProductA();
System.out.println("对productA初始化");
return productA;
}
}
class ProductA {
public void function() {
System.out.println("ProductA do something...");
}
}
完成了需求后,由于业务发展很快,没过几天,又有了新的需求,需要创建新的产品,产品B和产品C,经过我的分析,发现产品B和产品C在本质上是同一个类型的产品,固我创建了一个产品接口,同时修改了工厂类,以利于工厂方法的统一返回。
public class Factory {
//增加了产品之后,工厂需要跟据传入的产品标识来返回具体哪一个产品
public Product createProduct(String flag) {
Product product;
if ("ProductA".equals(flag)) {
product = new ProductA();
System.out.println("对productA初始化");
} else if ("ProductB".equals(flag)) {
product = new ProductB();
System.out.println("对productB初始化");
} else {
product = new ProductC();
System.out.println("对productC初始化");
}
//利用多态, 返回产品接口, 解耦
return product;
}
}
//为了能在工厂中统一返回,定义一个产品类,将将产品的公式功能放到接口中
interface Product {
void function();
}
//产品A
class ProductA implements Product {
public void function() {
System.out.println("ProductA do something...");
}
}
//产品B
class ProductB implements Product {
public void function() {
System.out.println("ProductB do something...");
}
}
//产品C
class ProductC implements Product {
public void function() {
System.out.println("ProductC do something...");
}
}
可能你已经注意到了,每当增加新的产品时,都需要修改工厂类,在工厂类的创建方法中增加一个 if else
,又违反了开闭原则。这时,就用到了工厂方法模式来对程序进行优化。
三、使用工厂方法设计模式对程序进行优化
优化方法:将工厂中创建产品的方法变为抽象方法,对每个不同的产品实现相应的方法。
与之前多个if else
相比,如果再增加其它产品,不需要修改原来的代码,只需要增加相应的工厂的实现类即可,符合开闭原则。
//使用工厂方法模式对工厂类进行优化,将工厂类中创建对象的方法变为抽象方法。
public interface Factory {
Product createProduct();
}
class ConcreteProductA implements Factory {
public Product createProduct() {
System.out.println("对productA初始化");
return new ProductA();
}
}
class ConcreteProductB implements Factory {
public Product createProduct() {
System.out.println("对productB初始化");
return new ProductB();
}
}
class ConcreteProductC implements Factory {
public Product createProduct() {
System.out.println("对productC初始化");
return new ProductC();
}
}
//抽象产品接口
interface Product {
void function();
}
//具体的产品实现类
class ProductA implements Product {
public void function() {
System.out.println("ProductA do something...");
}
}
class ProductB implements Product {
public void function() {
System.out.println("ProductB do something...");
}
}
class ProductC implements Product {
public void function() {
System.out.println("ProductC do something...");
}
}
测试类:
public static void main(String[] args) {
//直接通过相应的工厂实现类来创建产品对象, 使用接口Factory来去耦合
Factory factory = new ConcreteProductA();
Product product = factory.createProduct();
product.function();
}
四、总结
工厂方法的核心结构有四个角色,分别是抽象工厂、具体工厂、抽象产品、具体产品。一般具体工厂类中的字段为对应具体产品实例化所需的参数。
使用工厂方法模式可以达到解耦、复用和方便后期维护拓展的目的。比如说,具体工厂与具体产品一一对应,可以由不同的团队同时开发。如果不使用工厂方法模式,多个团队要在同一个工厂类中添加多个 if else
,麻烦,后期维护也不方便。