目录
一、简单工厂
简单工厂是一种类创建型模式,它又称静态工厂方法。在简单工厂模式中,可以根据参数的不同来返回不同类的实例。
1、模式结构
Factory:工厂角色,负责实现创建所有实例的内部逻辑,外部通过调用factoryMethod创建产品对象。
Product:抽象产品角色,所有具体产品的抽象父类。
ConcreteProduct:具体产品角色。
2、模式实例
一个汽车生产商承接了各种品牌汽车的生产,当为宝马汽车生产产品时只需要在调用该工厂的方法时传入参数“BM”即可创建相应产品,现用简单模式来模拟实现。
2.1 代码实现
(1)Car.java
public interface Car {
public void run();
}
(2)宝马工厂类:BMFactory.java
public class BMFactory implements Car{
@Override
public void run() {
System.out.println("宝马汽车疾驰中......");
}
}
(3)奔驰工厂类:BCFactory.java
public class BCFactory implements Car {
@Override
public void run() {
System.out.println("奔驰汽车飞驰中...");
}
}
(4)创建工厂类CarFactory.java
public class CarFactory {
public static Car productCar(String brand) throws Exception{
if(brand.equals("BM")){
System.out.println("汽车工厂生产宝马汽车...");
return new BMFactory();
}else if(brand.equals("BC")){
System.out.println("汽车工厂生产奔驰汽车...");
return new BCFactory();
}else{
throw new Exception("工厂暂时无法生产该汽车");
}
}
}
(5) 客户端调用工厂类Client.java
public class Client {
public static void main(String[] args) {
try
{
Car car;
String brand = XMLUtil.getBrandName();
car = CarFactory.productCar(brand);
car.run();
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
}
(6)XMLUtil.java
该类用于读取XML配置文件中的信息,并且进行实例化,该类的getBean方法用于从XML配置文件中提取品牌名称,并返回该品牌名称。这样的好处是需要修改产品信息时只需要修改XML配置文件中的信息,而无需修改代码。
public class XMLUtil {
//该方法用于从XML配置文件中提取品牌名称,并返回该品牌名称
public static String getBrandName()
{
try
{
/*
* javax.xml.parsers 包中的DocumentBuilderFactory用于创建DOM模式的解析器对象 ,
* DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,
* 这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。
*/
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); //得到一个创建DOM解析器的工厂
DocumentBuilder builder = dFactory.newDocumentBuilder(); //DOM解析器对象
Document doc;
doc = builder.parse(new File("./config/simpleFactory.xml")); //DOM解析器解析xml文件得到代表整个文档的Document对象
//获取包含品牌名称的文本节点
NodeList nl = doc.getElementsByTagName("carBrand"); //获得carBrand元素节点
Node classNode=nl.item(0).getFirstChild(); //获得第一个
String brandName=classNode.getNodeValue().trim(); //获得carBrand节点的属性值
return brandName;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
}
(7)XML配置文件:simpleFactory.xml
<config>
<carBrand>BM</carBrand>
</config>
3、模式分析
简单工厂模式可以降低系统的耦合度,在调用工厂类的工厂方法时,只需要传入一个简单的参数而无需知道具体的对象创建的细节,将参数保存在XML等配置文件中,在修改时无需修改java源码。
3.1 优点
简单工厂模式实现了对象的创建和使用的分离,创建时客户端无需知道具体产品的创建细节,只需传入参数即可,在一定程度上提高了系统的灵活性。
3.2 缺点
简单模式的缺点很明显,工厂类集中了系统中所有产品的创建逻辑,职责较为沉重,而增添新产品时,必须要修改工厂。
3.3 适用场景
简单工厂模式适用于工厂类负责创建的对象较少时,这样不会造成工厂方法中的业务逻辑过于复杂。
二、工厂方法
工厂方法模式简称工厂模式,是一种类创建型模式,工厂方法针对的是多个产品系列结构,是java中最常用的设计模式之一,是简单工厂的衍生,它符合开闭原则,实现了可扩展性。
1、模式结构
Product:抽象产品,产品对象的共同父类或共同拥有的接口。
ConcreteProduct:具体产品,具体产品有专门的具体工厂创建,一般一一对应。
Factory:抽象工厂,是工厂方法模式的核心。
ConcreteFactory:具体工厂,是实现抽象工厂接口的具体工厂类,用于创建产品对象。
2、模式实例
一个汽车生产商承接了各种品牌汽车的生产,将其原有的汽车工厂进行分割,为每种品牌的汽车各自设立一个子工厂,宝马汽车工厂专门生产宝马汽车,奔驰汽车厂专门生产奔驰汽车,如果再次承接了其他品牌汽车的生产合作,只需要添加一个对应的工厂即可,无需对原有的工厂进行修改。
2.1 应用场景类图
2.2 代码实现
(1)Car.java
public interface Car {
public void run();
}
(2)BMCar.java
public class BMCar implements Car {
@Override
public void run() {
System.out.println("宝马疾驰中...");
}
}
(3)BCCar.java
public class BCCar implements Car {
@Override
public void run() {
System.out.println("奔驰小汽车飞驰中....");
}
}
(4)CarFactory.java
public interface CarFactory {
public Car produceCar();
}
(5)BMFactory.java
public class BMFactory implements CarFactory {
public Car produceCar() {
System.out.println("宝马工厂生产宝马汽车中...");
return new BMCar();
}
}
(6)BCFactory.java
public class BCFactory implements CarFactory{
@Override
public Car produceCar() {
System.out.println("奔驰汽车厂生产汽车..");
return new BCCar();
}
}
(7)Client.java
public class Client {
public static void main(String[] args) {
Car car;
CarFactory carFactory;
carFactory = (CarFactory)XMLUtil.getBean();
car = carFactory.produceCar();
car.run();
}
}
(8)XMLUtil.java
public class XMLUtil {
public static Object getBean(){
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
try {
//获取doc解析器
DocumentBuilder dBuilder = dFactory.newDocumentBuilder();
Document document = dBuilder.parse(new File("./config/factoryMethod.xml"));
//获取doc文本节点
NodeList nList = document.getElementsByTagName("className");
Node classNode = nList.item(0).getFirstChild();
String carBrand =classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c=Class.forName(carBrand);
Object obj=c.newInstance();
return obj;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
(9)factoryMethod.xml
<config>
<className>gc.factoryMethod.BCFactory</className>
</config>
3、模式分析
工厂模式是简单工厂模式的进一步抽象和推广,它保持了简单工厂的优点,并克服了缺点,核心的工厂类不再负责所有产品的创建,而是交由具体的子工厂,增加具体产品时,只需要增加相应的具体工厂,而无需修改原有的工厂逻辑。
3.1 优点
能够让工厂自主确定创建何种产品,如何创建对象的细节封装在具体的工厂类中,在系统中加入新产品时,完全符合开闭原则。
3.2 缺点
工厂模式一定程度上增加了系统的抽象性和理解难度,系统中的类的个数会成对增加,增加了系统的复杂度,会带来一部分额外开销。
3.3 适用场景
第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。Java Collection中的iterator() 方法即属于这种情况。
第二种情况,只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的。
三、抽象工厂
抽象工厂模式是一种对象创建型模式,用于产品族的构建,抽象工厂模式针对的是多个产品族结构,一个产品族内有多个产品系列。
1、模式结构
AbstractFactory:抽象工厂,是该模式的核心。
ConcreteFactory:具体工厂,用于创建产品的实例,具有有选择合适的产品对象的逻辑。
AbstractProduct:抽象产品,工厂所创建的对象的父类。
ConcreteProduct:具体产品。
2、模式实例
一个汽车生产商承接了各种品牌汽车的生产,又可以生产多种种类的汽车,像公共汽车、小轿车等,相同品牌的汽车构成一个产品族,而相同类型的汽车又构成了一个产品等级结构,使用抽象工厂模式实现该应用。
2.1 应用场景类图
2.2 代码实现
(1)Car.java
public interface Car {
public void run();
}
(2)BMCar.java
public class BMCar implements Car{
@Override
public void run() {
System.out.println("宝马轿车行驶中...");
}
}
(3)BCCar.java
public class BCCar implements Car {
@Override
public void run() {
System.out.println("奔驰汽车行驶中...");
}
}
(4)Bus
public interface Bus {
public void pull();
}
(5)BMBusjava
public class BMBus implements Bus{
@Override
public void pull() {
System.out.println("宝马大巴拉载乘客中...");
}
}
(6)BCBus.java
public class BCBus implements Bus{
@Override
public void pull() {
System.out.println("奔驰大巴拉载乘客中....");
}
}
(7)Factory.java
public interface Factory {
public Bus produceBus();
public Car produceCar();
}
(8)BMFactory.java
public class BMFactory implements Factory{
@Override
public Bus produceBus() {
System.out.println("宝马汽车厂生产宝马大巴...");
return new BMBus();
}
@Override
public Car produceCar() {
System.out.println("宝马汽车厂生产宝马轿车...");
return new BMCar();
}
}
(9)BCFactory.java
public class BCFactory implements Factory{
@Override
public Bus produceBus() {
System.out.println("奔驰汽车厂生产奔驰大巴...");
return null;
}
@Override
public Car produceCar() {
System.out.println("奔驰汽车厂生产奔驰轿车...");
return null;
}
}
(10)Client.java
public class Client {
public static void main(String[] args) {
Bus bus;
Car car;
Factory factory = (Factory)XMLUtil.getBean();
bus = factory.produceBus();
bus.pull();
car = factory.produceCar();
car.run();
}
}
(11)XMLUtil.java
public class XMLUtil {
public static Object getBean(){
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder dBuilder = dFactory.newDocumentBuilder();
Document document = dBuilder.parse(new File("./config/abstractFactory.xml"));
NodeList nList = document.getElementsByTagName("className");
Node node = nList.item(0).getFirstChild();
String str = node.getNodeValue().trim();
Object object = Class.forName(str).newInstance();
return object;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
(12)abstractFactory.xml
<config>
<className>gc.abstractFactory.BMFactory</className>
</config>
3、模式分析
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
3.1 优点
分离了具体的类。客户通过抽象接口操纵实例,产品的类名也在具体工厂的实现中被分离,当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
3.2 缺点
难以支持新种类的产品。因为抽象工厂接口确定了可以被创建的产品集合,所以难以扩展抽象工厂以生产新种类的产品,增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了开闭原则。
3.3 适用场景
系统中有多于一个的产品族,但每次只使用其中某一产品族,属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
参考文献:设计模式(第2版).清华出版社