抽象工厂模式——初学JAVA设计模式

一、基本概念

前面所学的工厂方法模式引入等级结构,结局了简单工厂模式中工厂类职责太重的问题,缺点会产生大量的工厂类,势必增加系统的开销。

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

工厂角色

AbstractFactory(抽象工厂):用于声明生成抽象产品的方法(接口或抽象类)

ConcreteFactory(具体工厂):实现了抽象工厂声明的生成抽象产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中;

AbstractProduct(抽象产品):为每种产品声明接口,在抽象产品中定义了产品的抽象业务方法;

Product(具体产品):定义具体工厂生产的具体产品对象,实现抽象产品接口中定义的业务方法。

- AbstractFactory

可以定义为接口

public interface AbstractFactory{
        public  AbstractFactoryA createProduceA(); //工厂方法一
        public  AbstractFactoryA createProduceA(); //工厂方法二
}

也可以定义为抽象类(以下例子是按照继承抽象类形式)

abstract class AbstractFactory{
    public abstract AbstractFactoryA createProduceA(); //工厂方法一
    public abstract AbstractFactoryB createProduceB(); //工厂方法二
}

- ConcreteFactory

class ConceteFactory1 extends AbstractFactory{
    public AbstractFactoryA createProduceA(){
        return new createProduceA1();
    }
    public AbstractFactoryB createProduceB(){
        return new createProduceB1();
    }
    
}

- AbstractProduct

public interface AbstractProduct1 {
    public void Method1();
}
public interface AbstractProduct2 {
    public void Method2();

- ConcreteProduct

public class ConcreteProduct1 extends AbstractProduct1{
        public void Method1(){
            System.out.println("...");
        }
}
public class ConcreteProduct2 extends AbstractProduct2{
        public void Method2(){
            System.out.println("...");
        }
}

二、具体实例

类图

在这里插入图片描述

实现代码

- 抽象工厂:EFactory.java

package abstractF;
//电子工厂:实现此接口的有HaierFactory、TCLFactory
public interface EFactory {
    public Television produceTelevision();
    public AirConditioner produceAirConditioner();
}

- 具体工厂:HaierFactory.java

package abstractF;
/**
 * @Description:具体工厂
 */
public class HaierFactory implements EFactory {
    @Override
    public Television produceTelevision() {
        return new HaierTelevision();
    }
    @Override
    public AirConditioner produceAirConditioner() {
        return new HaierAirConditioner();
    }
}

- 具体工厂:TCLFactory.java

package abstractF;

/**
 * @Description:具体工厂
 */
public class TCLFactory implements EFactory {
    @Override
    public Television produceTelevision() {
        return new TCLTelevision();
    }

    @Override
    public AirConditioner produceAirConditioner() {
        return new TCLAirConditioner();
    }
}

- 具体产品:HaierAirConditioner.java

package abstractF;
public class HaierAirConditioner implements AirConditioner{

    @Override
    public void changeTemperature() {
        System.out.println("海尔空调改变温度中...");
    }
}

- 具体产品:HaierTelevision.java

package abstractF;
public class HaierTelevision implements Television{
    @Override
    public void play() {
        System.out.println("海尔电视播放中...");
    }
}

(后面省略TCLTelevision.java和TCLAirConditioner.java代码…)

- 配置类:XMLUtil.java

package abstractF;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;

public class XMLUtil {

	// 该方法用于从XML文件中提取品牌品牌名称,并返回该品牌名称
	public static Object getBean() {
		try {
			// 创建文档流
			DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = dFactory.newDocumentBuilder();
			Document doc;
			doc = builder.parse(new File("src\\abstractF\\config.xml"));
			// 获取包含类名的文本节点
			NodeList n1 = doc.getElementsByTagName("className");
			Node classNode = n1.item(0).getFirstChild(); // 这里稍微修改了一下
			String cName = classNode.getNodeValue();
			// 通过类名生成实例对象并将其返回
			Class c = Class.forName("abstractF."+cName);
			//这里要特别注意了:开始的还是直接写的是cName结果一直发现不了错误
			//后面才知道哟=要把配置文件放进包,并且要声明包名才可以找到相关类
			//另外一种方式是在配置文件config.xml输入数据时加上factory.
			
			Object obj = c.newInstance();
			return obj;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}

- 配置文件config.xml

<?xml version="1.0" ?>
<config>
	<className>HaierFactory</className>
</config>

- 客户端:Client.java

package abstractF;
public class Client {
    public static void main(String[] args) {
        try {
            EFactory factory;
            Television tv;
            AirConditioner ac;
            factory = (EFactory)XMLUtil.getBean();
            tv = factory.produceTelevision();
            tv.play();
            ac = factory.produceAirConditioner();
            ac.changeTemperature();
        }catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
    }
}

- 运行结果
在这里插入图片描述

三、小结

抽象工厂模式是工厂方法模式的进一步延伸,由于它提供了功能更为强大的工厂类并且具备
较好的可扩展性,在软件开发中得以广泛应用,尤其是在一些框架和API类库的设计中,例如
在Java语言的AWT(抽象窗口工具包)中就使用了抽象工厂模式,它使用抽象工厂模式来实
现在不同的操作系统中应用程序呈现与所在操作系统一致的外观界面。抽象工厂模式也是在
软件开发中最常用的设计模式之一。

优点

  • 隔离了具体类的生成,具体代码应用层代码隔离,无需关系细节,具有良好的封装性。

  • 横向扩展容易。增加新的产品族,支持“开闭原则”,只需直接增加产品族和对应产品。

  • 当产品族中多个对象被设计成一起工作时,保证将一系列产品同时创建,

缺点

  • 纵向扩展困难。增加产品等级结构(Computer),抽象工厂类(EFactory)也要添加该产品族的对应方法(use方法),这样一来所有的具体工厂类都要修改,严重违反开闭原则。

  • 增加了系统的抽象性和理解难度。

适用场景

  • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工
    厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。

  • 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来
    使得用户可以动态改变产品族,也可以很方便地增加新的产品族。

  • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。如同一操作
    系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统
    的,此时具有一个共同的约束条件:操作系统的类型。

  • 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的
    产品等级结构。

四、抽象工厂模式与工厂方法模式的区别

  • 工厂模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类
  • 抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类
    区别工厂方法模式:
    在这里插入图片描述

参考书籍《Java设计模式——刘伟第二版》

猜你喜欢

转载自blog.csdn.net/fazijiaidama/article/details/105858169