设计模式08---设计模式之抽象工厂模式(Abstract Factory)

1.场景模拟

举个生活中常见的例子:组装电脑,我们在组装电脑的时候,通常要选择一系列的配件,比如选择CPU时候,需要注意品牌,型号,针脚数目,主频,只有这些都确定下来,才能确定一个CPU。同样,主板也是这样的。对于装机工程师而言,他只知道装一台电脑需要使用相应的配件,具体的配件,还是由客户说了算。

2.一般的解决方案(简单工厂)

2.1CPU接口

package demo06.abstractfactory.example1;


/**
 * CPU的接口
 */
public interface CPUApi {
	/**
	 * 示意方法,CPU具有运算的功能
	 */
	public void calculate();
}

2.2主板接口

package demo06.abstractfactory.example1;

/**
 * 主板的接口
 */
public interface MainboardApi {
	/**
	 * 示意方法,主板都具有安装CPU的功能
	 */
	public void installCPU();
}

2.3 Inter CPU实现

package demo06.abstractfactory.example1;


/**
 * Intel的CPU实现
 */
public class IntelCPU implements CPUApi {
	/**
	 * CPU的针脚数目
	 */
	private int pins = 0;


	/**
	 * 构造方法,传入CPU的针脚数目
	 * 
	 * @param pins
	 *            CPU的针脚数目
	 */
	public IntelCPU(int pins) {
		this.pins = pins;
	}


	public void calculate() {
		System.out.println("now in Intel CPU,pins=" + pins);
	}
}

2.4 AMD的CPU实现

package demo06.abstractfactory.example1;


/**
 * AMD的CPU实现
 */
public class AMDCPU implements CPUApi {
	/**
	 * CPU的针脚数目
	 */
	private int pins = 0;


	/**
	 * 构造方法,传入CPU的针脚数目
	 * 
	 * @param pins
	 *            CPU的针脚数目
	 */
	public AMDCPU(int pins) {
		this.pins = pins;
	}


	public void calculate() {
		System.out.println("now in AMD CPU,pins=" + pins);
	}
}

2.5技嘉的主板实现

package demo06.abstractfactory.example1;


/**
 * 技嘉的主板
 */
public class GAMainboard implements MainboardApi {
	/**
	 * CPU插槽的孔数
	 */
	private int cpuHoles = 0;


	/**
	 * 构造方法,传入CPU插槽的孔数
	 * 
	 * @param cpuHoles
	 *            CPU插槽的孔数
	 */
	public GAMainboard(int cpuHoles) {
		this.cpuHoles = cpuHoles;
	}


	public void installCPU() {
		System.out.println("now in GAMainboard,cpuHoles=" + cpuHoles);
	}
}

2.6微星的主板

package demo06.abstractfactory.example1;


/**
 * 微星的主板
 */
public class MSIMainboard implements MainboardApi {
	/**
	 * CPU插槽的孔数
	 */
	private int cpuHoles = 0;


	/**
	 * 构造方法,传入CPU插槽的孔数
	 * 
	 * @param cpuHoles
	 *            CPU插槽的孔数
	 */
	public MSIMainboard(int cpuHoles) {
		this.cpuHoles = cpuHoles;
	}


	public void installCPU() {
		System.out.println("now in MSIMainboard,cpuHoles=" + cpuHoles);
	}
}

2.7创建CPU工厂

package demo06.abstractfactory.example1;
/**
 * 创建CPU的简单工厂
 */
public class CPUFactory {
	/**
	 * 创建CPU接口对象的方法
	 * @param type 选择CPU类型的参数
	 * @return CPU接口对象的方法
	 */
	public static CPUApi createCPUApi(int type){
		CPUApi cpu = null;
		//根据参数来选择并创建相应的CPU对象
		if(type==1){
			cpu = new IntelCPU(1156);
		}else if(type==2){
			cpu = new AMDCPU(939);
		}
		return cpu;
	}	
}

2.8创建主板工厂

package demo06.abstractfactory.example1;


/**
 * 创建主板的简单工厂
 */
public class MainboardFactory {
	/**
	 * 创建主板接口对象的方法
	 * 
	 * @param type
	 *            选择主板类型的参数
	 * @return 主板接口对象的方法
	 */
	public static MainboardApi createMainboardApi(int type) {
		MainboardApi mainboard = null;
		// 根据参数来选择并创建相应的主板对象
		if (type == 1) {
			mainboard = new GAMainboard(1156);
		} else if (type == 2) {
			mainboard = new MSIMainboard(939);
		}
		return mainboard;
	}
}

2.9工程师实现代码

package demo06.abstractfactory.example1;


/**
 * 装机工程师的类
 */
public class ComputerEngineer {
	/**
	 * 定义组装机器需要的CPU
	 */
	private CPUApi cpu = null;
	/**
	 * 定义组装机器需要的主板
	 */
	private MainboardApi mainboard = null;


	/**
	 * 装机过程
	 * 
	 * @param cpuType
	 *            客户选择所需CPU的类型
	 * @param mainboardType
	 *            客户选择所需主板的类型
	 */
	public void makeComputer(int cpuType, int mainboardType) {
		// 1:首先准备好装机所需要的配件
		prepareHardwares(cpuType, mainboardType);
		// 2:组装机器


		// 3:测试机器


		// 4:交付客户
	}


	/**
	 * 准备装机所需要的配件
	 * 
	 * @param cpuType
	 *            客户选择所需CPU的类型
	 * @param mainboardType
	 *            客户选择所需主板的类型
	 */
	private void prepareHardwares(int cpuType, int mainboardType) {
		// 这里要去准备CPU和主板的具体实现,为了示例简单,这里只准备这两个
		// 可是,装机工程师并不知道如何去创建,怎么办呢?


		// 直接找相应的工厂获取
		this.cpu = CPUFactory.createCPUApi(cpuType);
		this.mainboard = MainboardFactory.createMainboardApi(mainboardType);


		// 测试一下配件是否好用
		this.cpu.calculate();
		this.mainboard.installCPU();
	}
}

2.90客户端测试

package demo06.abstractfactory.example1;


public class Client {
	public static void main(String[] args) {
		// 创建装机工程师对象
		ComputerEngineer engineer = new ComputerEngineer();
		// 告诉装机工程师自己选择的配件,让装机工程师组装电脑
		engineer.makeComputer(1, 2);
	}
}

3.问题:

问题出现了:如果client传入的参数时1,2,那么装机不匹配就会失败,所以就会出现问题,如何解决呢?

4.解决方法(抽象工厂模式)

4.1模式定义:

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

4.2模式的结构和说明

 

5.示例代码(抽象工厂模式)

5.1抽象工厂接口

package demo06.abstractfactory.example2;


/**
 * 抽象工厂的接口,声明创建抽象产品对象的操作
 */
public interface AbstractFactory {
	/**
	 * 示例方法,创建抽象产品A的对象
	 * 
	 * @return 抽象产品A的对象
	 */
	public AbstractProductA createProductA();


	/**
	 * 示例方法,创建抽象产品B的对象
	 * 
	 * @return 抽象产品B的对象
	 */
	public AbstractProductB createProductB();
}

5.2产品A接口

package demo06.abstractfactory.example2;


/**
 * 抽象产品A的接口
 */
public interface AbstractProductA {
	// 定义抽象产品A相关的操作
}

5.3产品B接口

package demo06.abstractfactory.example2;


/**
 * 抽象产品B的接口
 */
public interface AbstractProductB {
	// 定义抽象产品B相关的操作
}

5.4产品A实现

package demo06.abstractfactory.example2;


/**
 * 产品A的具体实现
 */
public class ProductA1 implements AbstractProductA {
	// 实现产品A的接口中定义的操作
}


package demo06.abstractfactory.example2;


/**
 * 产品A的具体实现
 */
public class ProductA2 implements AbstractProductA {
	// 实现产品A的接口中定义的操作
}

5.5产品B实现

package demo06.abstractfactory.example2;


/**
 * 产品B的具体实现
 */
public class ProductB1 implements AbstractProductB {
	// 实现产品B的接口中定义的操作
}


package demo06.abstractfactory.example2;


/**
 * 产品B的具体实现
 */
public class ProductB2 implements AbstractProductB {
	// 实现产品B的接口中定义的操作
}

5.6具体工厂实现

package demo06.abstractfactory.example2;


/**
 * 具体的工厂实现对象,实现创建具体的产品对象的操作
 */
public class ConcreteFactory1 implements AbstractFactory {


	public AbstractProductA createProductA() {
		return new ProductA1();
	}
	public AbstractProductB createProductB() {
		return new ProductB1();
	}
}


package demo06.abstractfactory.example2;


/**
 * 具体的工厂实现对象,实现创建具体的产品对象的操作
 */
public class ConcreteFactory2 implements AbstractFactory {


	public AbstractProductA createProductA() {
		return new ProductA2();
	}
	public AbstractProductB createProductB() {
		return new ProductB2();
	}
}

5.7客户端

package demo06.abstractfactory.example2;


public class Client {


	public static void main(String[] args) {
		// 创建抽象工厂对象
		AbstractFactory af = new ConcreteFactory1();
		// 通过抽象工厂来获取一系列的对象,如产品A和产品B
		af.createProductA();
		af.createProductB();
	}
}

6.重写示例代码

6.1结构图

 

6.2抽象工厂接口

package demo06.abstractfactory.example3;


/**
 * 抽象工厂的接口,声明创建抽象产品对象的操作
 */
public interface AbstractFactory {
	/**
	 * 创建CPU的对象
	 * 
	 * @return CPU的对象
	 */
	public CPUApi createCPUApi();


	/**
	 * 创建主板的对象
	 * 
	 * @return 主板的对象
	 */
	public MainboardApi createMainboardApi();
}

6.3装机方案一

package demo06.abstractfactory.example3;


/**
 * 装机方案一:Intel 的CPU + 技嘉的主板 这里创建CPU和主板对象的时候,是对应的,能匹配上的
 */
public class Schema1 implements AbstractFactory {
	public CPUApi createCPUApi() {
		return new IntelCPU(1156);
	}


	public MainboardApi createMainboardApi() {
		return new GAMainboard(1156);
	}
}

6.4装机方案二

package demo06.abstractfactory.example3;


/**
 * 装机方案二:AMD的CPU + 微星的主板 这里创建CPU和主板对象的时候,是对应的,能匹配上的
 */
public class Schema2 implements AbstractFactory {
	public CPUApi createCPUApi() {
		return new AMDCPU(939);
	}


	public MainboardApi createMainboardApi() {
		return new MSIMainboard(939);
	}
}

6.5装机工程师

package demo06.abstractfactory.example3;


/**
 * 装机工程师的类
 */
public class ComputerEngineer {
	/**
	 * 定义组装机器需要的CPU
	 */
	private CPUApi cpu = null;
	/**
	 * 定义组装机器需要的主板
	 */
	private MainboardApi mainboard = null;


	/**
	 * 装机过程
	 * 
	 * @param schema
	 *            客户选择的装机方案
	 */
	public void makeComputer(AbstractFactory schema) {
		// 1:首先准备好装机所需要的配件
		prepareHardwares(schema);
		// 2:组装机器


		// 3:测试机器


		// 4:交付客户
	}


	/**
	 * 准备装机所需要的配件
	 * 
	 * @param schema
	 *            客户选择的装机方案
	 */
	private void prepareHardwares(AbstractFactory schema) {
		// 这里要去准备CPU和主板的具体实现,为了示例简单,这里只准备这两个
		// 可是,装机工程师并不知道如何去创建,怎么办呢?


		// 使用抽象工厂来获取相应的接口对象
		this.cpu = schema.createCPUApi();
		this.mainboard = schema.createMainboardApi();


		// 测试一下配件是否好用
		this.cpu.calculate();
		this.mainboard.installCPU();
	}
}

6.6客户端使用

package demo06.abstractfactory.example3;


public class Client {
	public static void main(String[] args) {
		// 创建装机工程师对象
		ComputerEngineer engineer = new ComputerEngineer();
		// 客户选择并创建需要使用的装机方案对象
		AbstractFactory schema = new Schema1();
		// 告诉装机工程师自己选择的装机方案,让装机工程师组装电脑
		engineer.makeComputer(schema);
	}
}

7.抽象工厂模式讲解

7.1抽象工厂和DAO

DAO是数据访问对象,是J2EE中的一种标准的模式,是为了解决访问数据不同而产生的一种设计模式。这种设计模式简言之是:分层设计的思想。
在实现DAO模式的时候,多用工厂的策略,最常用的就是抽象工厂模式,当然最好结合工厂方法模式。

7.2抽象工厂的优缺点

优点:分离接口和实现
使得切换产品簇更加容易。
缺点:不太容易扩展新的产品
容易造成类层次复杂

7.3抽象工厂模式的本质

选择产品簇的实现

posted @ 2013-06-29 22:58  坚固66  阅读(170)  评论(0编辑  收藏  举报