Java设计模式精讲---简单工厂模式
23种设计模式,首先先来学习创建型模式的5个模式。
创建型模式
创建型模式关注对象的创建过程。创建型模式对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离,对用户隐藏了类的实例的创建细节。
在创建型模式中有工厂方法模式和抽象工厂模式。所以在学习创建型模式之前,先来学习一下简单工厂模式,它是学习其他工厂模式的基础。
简单工厂模式概述
简单工厂模式就是将需要创建的各种不同产品对象的相关代码封装到不同的类中,这些类称为具体产品类。而将他们的公共代码进行抽象和提取之后封装在一个抽象产品类中,每一个具体产品类都是抽象产品类的子类;然后提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入的参数不同创建不同的具体产品对象;客户端只需要调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象。
也就是说,简单工厂模式的结构主要分为3部分:工厂角色、抽象产品角色、具体产品角色。
简单工厂模式实现
下面给出简单工厂模式的一段示例代码
package designMode.creationalPatterns.SimpleFactoryPattern;
//简单工厂模式---抽象产品类
public abstract class Product {//所有产品类的公共业务方法public void methodSame(){System.out.println("抽象产品类方法");}//声明抽象业务方法public abstract void methodDiff();}
package designMode.creationalPatterns.SimpleFactoryPattern;
//简单工厂模式----具体产品类
public class ConcreteProductA extends Product{//实现业务方法@Overridepublic void methodDiff() {System.out.println("具体产品类实现业务方法A");}
}
package designMode.creationalPatterns.SimpleFactoryPattern;
//简单工厂模式----具体产品类
public class ConcreteProductB extends Product{//实现业务方法@Overridepublic void methodDiff() {System.out.println("具体产品类实现业务方法B");}
}
package designMode.creationalPatterns.SimpleFactoryPattern;
//简单工厂模式---核心类---工厂类
public class Factory {//静态工厂方法public static Product createProduct(String type){Product product = null;if(type.equalsIgnoreCase("A")){//初始化设置productproduct = new ConcreteProductA();}else if(type.equalsIgnoreCase("B")){//初始化设置productproduct = new ConcreteProductB();}return product;}
}
代码运行结果:具体产品类实现业务方法A
抽象产品类方法Process finished with exit code 0
关键代码详解
1.为什么工厂类中的工厂方法要用静态方法?
答:使用静态方法这样就无需实例化工厂类,直接通过类名调用,简化使用流程,降低开销。
2.equalsIgnoreCase方法的作用:比较忽略大小写之后的两个字符串是否相等。
上述实例在创建具体产品对象时必须通过修改客户端代码中的静态工厂方法的参数来更换具体产品对象,客户端代码需要重新编译,这对于客户端而言违反了开闭原则。下面介绍一种常用的解决方案,可以实现在不修改客户端代码的前提下让客户端能够更换具体产品对象。
首先可以将静态工厂方法的参数存储在XML格式的配置文件中,例如:
<?xml version = "1.0"?>
<config><chartType>histogram</chartType>
</config>再通过一个工具类XMLUtil来读取配置文件中的字符串参数。XMLUtil类的代码如下:
package designpatterns.simplefactory;
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;}}
}在引入了配置文件和工具类XMLUtil之后,客户端代码修改如下:
//designpatterns.simplefactory.Client.java
package designpatterns.simplefactory;
public class Client {public static void main(String args[]) {Chart chart;String type = XMLUtil.getChartType(); //读取配置文件中的参数chart = ChartFactory.getChart(type); //创建产品对象chart.display();}
}不难发现,在上述客户端代码中不包含任何与具体对象相关的信息,如果需要更换具体对象,只需修改配置文件config.xml,无需修改任何源代码,符合开闭原则。
关于创建对象
Java语言中创建对象的6种方式:
(1)使用new关键字直接创建对象
(2)通过反射机制创建对象
(3)通过克隆方法创建对象
(4)通过工厂类创建对象
(5)通过序列化与反序列化创建对象
(6)通过单例模式创建对象(后面会学到)
所有的工厂模式都强调一点:两个类A和B之间的关系应该仅仅是A创建B或是A使用B,而不能两种关系都有。将对象的创建和使用分离,使得系统更加符合单一职责原则,有利于对功能的复用和系统的维护。
简单工厂模式的简化
有时候,为了简化简单工厂模式,可以将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类中。代码示例如下:
public abstract class Product {public static Product factoryMewthod(String args){if ("A".equalsIgnoreCase(args)){return new ConcreteProductA();} else if ("B".equalsIgnoreCase(args)) {return new ConcreteProductB();}return null;}public abstract void operation();
}
客户端可以通过调用产品父类的静态工厂方法,根据参数的不同创建不同类型的产品子类对象,这种做法在很多类库和框架中也广泛存在。
简单工厂模式的优/缺点与适用环境
简单工厂模式的优点
简单工厂模式的优点主要如下:
(1)工厂类包含必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离
(2)客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以在一定程度上减少使用者的记忆量。
(3)通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
简单工厂模式的缺点
简单工厂模式的缺点主要如下:
(1)由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。
(2)使用简单工厂模式势必会增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度。
(3)系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
(4)简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
简单工厂模式适用环境
在以下情况下可以考虑使用简单工厂模式:
(1)工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
(2)客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
