文章目录
![](https://img-blog.csdnimg.cn/img_convert/9a72ac61fbd1e07acf2be25f238179e4.png)
代码实现:https://github.com/nateshao/design-demo/tree/main/JavaDesignPatterns/simplefactory
1. 创建型模式概述
创建型模式(Creational Pattern)
- 关注对象的创建过程
- 对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离,对用户隐藏了类的实例的创建细节
- 如何将对象的创建和使用分离,让用户在使用对象时无须关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修改和扩展
![](https://gitee.com/nateshao/images/raw/master/img/20211009185427.png)
模式名称 | 定 义 |
---|---|
简单工厂模式(Simple Factory Pattern) | 定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。 |
工厂方法模式(Factory Method Pattern) | 定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。 |
抽象工厂模式(Abstract Factory Pattern) | 提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。 |
建造者模式(Builder Pattern) | 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 |
原型模式(Prototype Pattern) | 使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。 |
单例模式(Singleton Pattern) | 确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。 |
2. 简单工厂模式概述
![](https://gitee.com/nateshao/images/raw/master/img/20211009190401.png)
简单工厂模式基本实现流程
**具体产品类:**将需要创建的各种不同产品对象的相关代码封装到具体产品类中
**抽象产品类:**将具体产品类公共的代码进行抽象和提取后封装在一个抽象产品类中
**工厂类:**提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入参数的不同创建不同的具体产品对象
**客户端:**只需调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象
if(arg.equalsIgnoreCase("Apple")) {
return new Apple();
}
else if(arg.equalsIgnoreCase("Banana")) {
return new Banana();
}
else {
......
}
简单工厂模式 (Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
在简单工厂模式中用于创建实例的方法通常是静态(static)方法,因此又被称为静态工厂方法(Static Factory Method)模式
要点:如果需要什么,只需要传入一个正确的参数,就可以获取所需要的对象,而无须知道其创建细节
简单工厂模式结构:简单工厂模式包含以下3个角色:
- Factory(工厂角色)
- Product(抽象产品角色)
- ConcreteProduct(具体产品角色)
![](https://gitee.com/nateshao/images/raw/master/img/20211009190930.png)
简单工厂模式的代码实现
Product.java
// 典型的抽象产品类代码:
public abstract class Product {
//所有产品类的公共业务方法
public void methodSame() {
//公共方法的实现
}
//声明抽象业务方法
public abstract void methodDiff();
}
ConcreteProduct.java
// 典型的具体产品类代码:
public class ConcreteProduct extends Product{
//实现业务方法
public void methodDiff() {
//业务方法的实现
}
}
Factory.java
public class Factory {
//静态工厂方法
public static Product getProduct(String arg) {
Product product = null;
if (arg.equalsIgnoreCase("A")) {
product = new ConcreteProductA();
//初始化设置product
}
else if (arg.equalsIgnoreCase("B")) {
product = new ConcreteProductB();
//初始化设置product
}
return product;
}
}
Client.java
// 典型的客户端代码:
public class Client {
public static void main(String args[]) {
Product product;
product = Factory.getProduct("A"); //通过工厂类创建产品对象
product.methodSame();
product.methodDiff();
}
}
简单工厂模式的应用实例
某软件公司要基于Java语言开发一套图表库,该图表库可以为应用系统提供多种不同外观的图表,例如柱状图(HistogramChart)、饼状图(PieChart)、折线图(LineChart)等。该软件公司图表库设计人员希望为应用系统开发人员提供一套灵活易用的图表库,通过设置不同的参数即可得到不同类型的图表,而且可以较为方便地对图表库进行扩展,以便能够在将来增加一些新类型的图表。
现使用简单工厂模式来设计该图表库。
- 实例代码
- Chart:抽象图表接口,充当抽象产品类
- HistogramChart:柱状图类,充当具体产品类
- PieChart:饼状图类,充当具体产品类
- LineChart:折线图类,充当具体产品类
- ChartFactory:图表工厂类,充当工厂类
- Client:客户端测试类
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
public class XMLUtil {
//该方法用于从XML配置文件中提取图表类型,并返回类型名
public static String getChartType() {
try {
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("src//designpatterns//simplefactory//config.xml"));
//获取包含图表类型的文本结点
NodeList nl = doc.getElementsByTagName("chartType");
Node classNode = nl.item(0).getFirstChild();
String chartType = classNode.getNodeValue().trim();
return chartType;
}
catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
![](https://gitee.com/nateshao/images/raw/master/img/20211009191952.png)
创建对象与使用对象
Java语言创建对象的几种方式
- 使用new关键字直接创建对象
- 通过反射机制创建对象
- 通过克隆方法创建对象
- 通过工厂类创建对象
实例分析
public class LoginAction {
private UserDAO udao;
public LoginAction() {
udao = new JDBCUserDAO(); //创建对象
}
public String execute() {
//其他代码
udao.findUserById(); //使用对象
//其他代码
}
}
若改为HibernateUserDAO必须修改源代码,违背开闭原则
所以,引入工厂类UserDAOFactory
![](https://gitee.com/nateshao/images/raw/master/img/20211009192411.png)
- 如果
UserDAO
的某个子类的构造函数发生改变或者需要添加或移除不同的子类,只要维护UserDAOFactory
的代码,不会影响到LoginAction
- 如果
UserDAO
的接口发生改变,例如添加、移除方法或改变方法名,只需要修改LoginAction
,不会给UserDAOFactory
带来任何影响
两个类A和B之间的关系应该仅仅是A创建B或者是A使用B,而不能两种关系都有。将对象的创建和使用分离,使得系统更加符合单一职责原则,有利于对功能的复用和系统的维护。
将对象的创建与使用分离的其他好处
- 防止用来实例化一个类的数据和代码在多个类中到处都是,可以将有关创建的知识搬移到一个工厂类中,解决代码重复、创建蔓延的问题。
- 构造函数的名字都与类名相同,从构造函数和参数列表中大家很难了解不同构造函数所构造的产品的差异 à 将对象的创建过程封装在工厂类中,可以提供一系列名字完全不同的工厂方法,每一个工厂方法对应一个构造函数,客户端可以以一种更加可读、易懂的方式来创建对象
何时不需要工厂?
- 无须为系统中的每一个类都配备一个工厂类
- 如果一个类很简单,而且不存在太多变化,其构造过程也很简单,此时就无须为其提供工厂类,直接在使用之前实例化即可
- 否则会导致工厂泛滥,增加系统的复杂度
- 例如:java.lang.String
简单工厂模式的简化
将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类中
简单工厂模式的优缺点与适用环境
模式优点
- 实现了对象创建和使用的分离
- 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性
模式缺点
- 工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响
- 增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度
- 系统扩展困难,一旦添加新产品不得不修改工厂逻辑
- 由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构,工厂类不能得到很好地扩展
模式适用环境
- 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心
式缺点**
- 工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响
- 增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度
- 系统扩展困难,一旦添加新产品不得不修改工厂逻辑
- 由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构,工厂类不能得到很好地扩展
模式适用环境
- 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心