1. 简单设计模式

简单工厂模式

1. 基本流程

首先将需要创建的各种不同对象(例如各种不同的Chart对象)的相关代码封装到不同的类 中,这些类称为具体产品类,而将它们公共的代码进行抽象和提取后封装在一个抽象产品类中,每一个具体产品类都是抽象产品类的子类;然后提供一个工厂类用于创建各种产品,在 工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入的参数不同创建不同的具体 产品对象;客户端只需调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象。

2. 简单工厂模式定义

简单工厂模式(Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的 实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于**创建实例的方法是 静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式**,它属 于类创建型模式。

3. 简单工厂模式的要点

当你需要什么产品,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。

简单工厂模式结构如下:

image-20211015155348572

4. 简单工厂模式包含的角色

  • Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方factoryMethod(),它的返回类型为抽象产品类型Product。
  • Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法, 因为所有创建的具体产品对象都是其子类对象。
  • ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充 当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在 抽象产品中声明的抽象方法。

5. 简单工厂例子

image-20211020180919019

抽象产品和具体产品

//抽象图表接口:抽象产品类
interface Chart {
public void display();
}
//柱状图类:具体产品类
class HistogramChart implements Chart {
public HistogramChart() {
System.out.println("创建柱状图!");
}
public void display() {
System.out.println("显示柱状图!");
}
}
//饼状图类:具体产品类
class PieChart implements Chart {
public PieChart() {
System.out.println("创建饼状图!");
}
public void display() {
System.out.println("显示饼状图!");
}
}
//折线图类:具体产品类
class LineChart implements Chart {
public LineChart() {
System.out.println("创建折线图!");
}
public void display() {
System.out.println("显示折线图!");
}
}

简单工厂

//图表工厂类:工厂类
class ChartFactory {
//静态工厂方法
public static Chart getChart(String type) {
Chart chart = null;
if (type.equalsIgnoreCase("histogram")) {
chart = new HistogramChart();
System.out.println("初始化设置柱状图!");
}
else if (type.equalsIgnoreCase("pie")) {
chart = new PieChart();
System.out.println("初始化设置饼状图!");
}
else if (type.equalsIgnoreCase("line")) {
chart = new LineChart();
System.out.println("初始化设置折线图!");
}
return chart;
}
}

在客户端代码中,我们通过调用工厂类的工厂方法即可得到产品对象,典型代码如下所示:

class Client {
public static void main(String args[]) {
Chart chart;
chart = ChartFactory.getChart("histogram"); //通过静态工厂方法创建产品
chart.display();
}
}

每更换一个Chart对象都需要修改客户 端代码中静态工厂方法的参数,客户端代码将要重新编译,这对于客户端而言,违反了“开闭 原则”,我们可以将静态工厂方法的参数存储在XML或properties格式的配置文件中,如下config.xml所 示:

<?xml version="1.0"?>
<config>
<chartType>histogram</chartType>
</config>

再通过一个工具类XMLUtil来读取配置文件中的字符串参数,XMLUtil类的代码如下所示:

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("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;
}
}
}

在引入了配置文件和工具类XMLUtil之后,客户端代码修改如下:

class Client {
public static void main(String args[]) {
Chart chart;
String type = XMLUtil.getChartType(); //读取配置文件中的参数
chart = ChartFactory.getChart(type); //创建产品对象
chart.display();
}
}

不难发现,在上述客户端代码中不包含任何与具体图表对象相关的信息,如果需要更换具体 图表对象,只需修改配置文件config.xml,无须修改任何源代码,符合“开闭原则”

不过如果添加了新的产品就需要修改工厂的代码,添加if语句判断新产品,这个不符合开闭原则

6. 简单工厂模式的简化

有时候,为了简化简单工厂模式,我们可以将抽象产品类和工厂类合并,将静态工厂方法移 至抽象产品类中,如图:

image-20211020183139749

客户端可以通过产品父类的静态工厂方法,根据参数的不同创建不同类型的产品子 类对象,这种做法在JDK等类库和框架中也广泛存在。

简单工厂模式总结

简单工厂模式提供了专门的工厂类用于创建对象,将对象的创建和对象的使用分离开

主要优点

  1. 工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以 免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分 离。
  2. 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可, 对于一些复杂的类名,通过简单工厂模式可以在一定程度减少使用者的记忆量。
  3. 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类, 在一定程度上提高了系统的灵活性。

主要缺点

  1. 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受 到影响。
  2. 使用简单工厂模式势必会增加系统中类的个数(引入了新的工厂类),增加了系统的复杂 度和理解难度
  3. 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成 工厂逻辑过于复杂,不利于系统的扩展和维护。
  4. 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构

适用场景

  1. 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太 过复杂。
  2. 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
posted @   墨镜一戴谁也不爱  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示