1.问 : 很多时候通过反射机制就可以很灵活地创建对象,为毛还要工厂?
将对象的创建和使用分开,单一职责。两个类A和B之间的关系应该仅仅是A创建B或是A使用B,而不能两种关系都有。
与一个对象相关的职责通常有三类:对象本身所具有的职责、创建对象的职责和使用对象的职责
在Java语言中,我们通常有以下几种创建对象的方式:
(1) 使用new关键字直接创建对象;
(2) 通过反射机制创建对象;
(3) 通过clone()方法创建对象;
(4) 通过工厂类创建对象。
new 灵活性不好,不符合开闭原则。
将对象的创建和使用分离还有一个好处:防止用来实例化一个类的数据和代码在多个类中到处都是,可以将有关创建的知识搬移到一个工厂类中
一个类可能拥有多个构造函数,构造函数名字都与类名相同,将对象的创建过程封装在工厂类中,我们可以提供一系列名字完全不同的工厂方法,每一个工厂方法对应一个构造函数,客户端可以以一种更加可读、易懂的方式来创建对象。
2.简单工厂模式——提供一个统一的工厂类来创建所有的产品对象
abstract class Product { //所有产品类的公共业务方法 public void methodSame() { //公共方法的实现 } //声明抽象业务方法 public abstract void methodDiff();}
class ConcreteProduct extends Product {
//实现业务方法
public void methodDiff() {
//业务方法的实现
}
}
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; } }
class Client {
public static void main(String args[]) {
Product product;
product = Factory.getProduct("A"); //通过工厂类创建产品对象
product.methodSame();
product.methodDiff();
}
}
我们可以将静态工厂方法的参数存储在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;
}
}
}
有时候,为了简化简单工厂模式,我们可以将抽象产品类和工厂类合并,将静态工厂方法移至抽象产品类中。
缺点:
(1) 工厂类过于庞大,包含了大量的if…else…代码,导致维护和测试难度增大;
(2) 系统扩展不灵活,如果增加新类型的产品类,必须修改静态工厂方法的业务逻辑,违反了“开闭原则”。
适用场景
(1) 工厂类负责创建的对象比较少,工厂方法中的业务逻辑不会太过复杂。
(2) 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
结论:对象种类比较少的时候用。
3.工厂方法—针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构
//*****引入抽象工厂interface Factory { public Product factoryMethod(); }w class ConcreteFactory implements Factory { public Product factoryMethod() { return new ConcreteProduct(); } Factory factory; factory = new ConcreteFactory(); //可通过配置文件实现 Product product; product = factory.factoryMethod();}