工厂模式三兄弟之工厂方法模式
1.什么是工厂方法?
工厂方法模式(FACTORY METHOD)是一种常用的创建型设计模式,此模式的核心精神是封装类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂,具体工厂,抽象产品,具体产品. 工厂方法模式也是简单工厂的进化版本,为什么这么说呢,继续往下看就明白了.
2.为什么用工厂方法模式?
在上一篇中介绍过 简单工厂 了,虽然说简单工厂已经可以解决部分问题了,但是也存在一个很严重的缺陷,当需求变化小的时候可能不太容易发现,但是当需求(具体产品)的更改持续增加的时候,就要频繁的更改工厂的代码,这也就违背了开闭原则,显然是不好的设计,当判断逻辑变得臃肿时,改一个逻辑就会变得小心翼翼外加困难重重,所以工厂方法模式也就这么应运而生了,而他是怎么解决这个问题的呢?其实也就是把开闭原则利用上,把其中个性化的部分提取出来设置成独立的个体,然后通过注入的方式去让整个工厂更灵活,更容易拓展,也就达到了解耦和复用的作用.
3.工厂方法模式怎么用?
先来看看简单工厂模式的UML模型:
由此可以看出,抽象工厂模式主要是由四部分组成:抽象工厂,具体工厂,抽象产品,具体产品;通过个性化后的工厂生产个性化的对象,已达到相互隔离的效果.同时也满足了开闭原则.它即继承了简单工厂模式的优点,又还弥补了简单工厂模式的不足.所以在使用上来说,工厂方法模式也是使用频率最高的设计模式之一.下面来看具体代码:
抽象工厂:
/**
* @author zhangcq
* @Description: 抽象工厂
* @Time: 2019/3/4 14:04
* @Version 1.0
*/
public abstract class LogsFactory {
public void print() {
Logs logger = this.createLogger();
logger.print();
}
protected abstract Logs createLogger();
}
DB工厂:
/**
* @author zhangcq
* @Description: DB工厂
* @Time: 2019/3/8 13:36
* @Version 1.0
*/
public class DBLogsFactory extends LogsFactory {
@Override
protected Logs createLogger() {
return new LogsDB();
}
}
File工厂:
/**
* @author zhangcq
* @Description: File工厂
* @Time: 2019/3/8 13:36
* @Version 1.0
*/
public class FileLogsFactory extends LogsFactory {
@Override
protected Logs createLogger() {
return new LogsFile();
}
}
抽象产品:
/**
* @author zhangcq
* @Description: 抽象产品
* @Time: 2019/3/4 14:04
* @Version 1.0
*/
public interface Logs {
void print();
}
DB产品:
/**
* @author zhangcq
* @Description: DB产品
* @Time: 2019/3/4 14:16
* @Version 1.0
*/
public class LogsDB implements Logs {
@Override
public void print() {
System.out.println("将日志输出到数据库...");
}
}
File产品:
/**
* @author zhangcq
* @Description: File产品
* @Time: 2019/3/4 14:17
* @Version 1.0
*/
public class LogsFile implements Logs {
@Override
public void print() {
System.out.println("将日志输出到文件...");
}
}
客户端:
/**
* @author zhangcq
* @Description: 客户端
* @Time: 2019/3/4 14:18
* @Version 1.0
*/
public class LogsClient {
public static void main(String[] args) {
LogsFactory logsFactory;
logsFactory = new DBLogsFactory();
logsFactory.print();
logsFactory = new FileLogsFactory();
logsFactory.print();
}
}
4.工厂方法模式总结
1. 主要优点
工厂方法模式的主要优点如下:
(1) 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
(2) 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够让工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,就正是因为所有的具体工厂类都具有同一抽象父类。
(3) 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
2. 主要缺点
工厂方法模式的主要缺点如下:
(1) 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
(2) 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
3. 适用场景
在以下情况下可以考虑使用工厂方法模式:
(1) 客户端不知道它所需要的对象的类。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建,可将具体工厂类的类名存储在配置文件或数据库中。
(2) 抽象工厂类通过其子类来指定创建哪个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
_____________________________________________________________________________________________________代码地址:github