[设计模式]-抽象工厂模式ing

定义:

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

结构:

抽象工厂模式中的角色和工厂方法模式的完全相同,由四个部分组成:

  • 抽象工厂:工厂方法模式的核心,与应用程序无关。是具体工厂角色必须实现的接口或必须继承的父类
  • 具体工厂:由应用程序调用以创建对应具体的产品的对象
  • 抽象产品:产品接口
  • 具体产品:具体的产品实现对象,通常在具体工厂里,会选择具体的产品实现对象,来创建符合抽象工厂定义的方法返回的产品类型的对象

场景实例:组装电脑,选择组装电脑的配件

客户选择不同的CPU和主板,在最终确定装机方案之前,还需整体考虑各个配件之间的兼容性。比如CPU针脚数和主板提供的CPU插口不兼容,是无法组装的。也就是说,装机方案是有整体性的,里面选择的各个配件之间是有关联的

简单起见,使用简单工厂实现:

  • 抽象接口
/**
 * CPU接口<产品簇1>
 */
public interface CPUApi {
	//实例方法,CPU运算的功能
	public void calculate();
}
/**
 * 主板接口<产品簇2>
 */
public interface MainboardApi {
	//实例方法,安装CPU的功能
	public void installCPU();
}
  • 具体产品实现
class IntelCPU implements CPUApi{
	//CPU针脚数
	private int pins=0;
	public IntelCPU(int pins){
		this.pins=pins;
	}

	@Override
	public void calculate() {
		System.out.println("now in Intel CPU ,pins="+pins);
	}
}
class AMDCPU implements CPUApi{
	//CPU针脚数
	private int pins=0;
	public AMDCPU(int pins){
		this.pins=pins;
	}

	@Override
	public void calculate() {
		System.out.println("now in AMD CPU ,pins="+pins);
	}
}
/**
 * Intel主板
 */
class IntelMainboard implements MainboardApi{
	//CPU插槽孔数
	private int cpuHoles = 0;

	public IntelMainboard(int cpuHoles){
		this.cpuHoles=cpuHoles;
	}

	@Override
	public void installCPU() {
		System.out.println("Intel 主板的CPU插槽孔数是:"+cpuHoles);
	}
}
/**
 * AMD主板
 */
class AMDMainboard implements MainboardApi{
	//CPU插槽孔数
	private int cpuHoles = 0;

	public AMDMainboard(int cpuHoles){
		this.cpuHoles=cpuHoles;
	}

	@Override
	public void installCPU() {
		System.out.println("AMD 主板的CPU插槽孔数是:"+cpuHoles);
	}
}
  • 工厂方法
/**
 * CPU工厂
 */
public class CPUFactory {
	public static CPUApi createCPU(int type){
		CPUApi cpu=null;
		if(type==1){
			cpu=new IntelCPU(1156);
		}else{
			cpu=new AMDCPU(939);
		}
		return cpu;
	}
}
/**
 * 主板工厂
 */
class MainboardFactory {
	public static MainboardApi createMainboard(int type){
		MainboardApi mainboard=null;
		if(type==1){
			mainboard=new IntelMainboard(1156);
		}else{
			mainboard=new AMDMainboard(939);
		}
		return mainboard;
	}
}
  • 装机工程师

/**
 * 装机工程师,不知道具体实现,只根据客户要求组装电脑
 */
class ComputerEngineer{
	private CPUApi cpu=null;
	private MainboardApi mainboard=null;
	//根据方案组装电脑
	public void makeComputer(int cpuType,int mainboardType){
		this.cpu=CPUFactory.createCPU(cpuType);
		this.mainboard=MainboardFactory.createMainboard(mainboardType);

		cpu.calculate();
		mainboard.installCPU();
	}
}

  • 客户端

public class Client {
	public static void main(String[] args) {
		//创建工程师对象
		ComputerEngineer engineer=new ComputerEngineer();
		//告诉工程师自己的方案,由工程师组装
		engineer.makeComputer(1,2);
		//output:	now in Intel CPU ,pins=1156
		//   		AMD 主板的CPU插槽孔数是:28
	}
}

有何问题?

上面的实现虽然通过简单工厂解决了,但有一个问题没解决,那就是这些CPU对象和主板对象是有关系的,是需要互相匹配的。而上面的实现并没有维护这种关联关系,如客户端测试传入1,2参数就会导致无法组装。

抽象工厂模式来解决问题

  • 抽象工厂

/**
 * 抽象工厂:声明创建抽象产品对象的操作
 *@Author: April
 *@Date: 2014-7-5
 */
public interface AbstractFactory {
	//创建CPU的对象
	public CPUApi createCPUApi();
	//创建主板的对象
	public MainboardApi createMainboardApi();
}

  • 抽象工厂的实现:即装机方案

/**
 * 装机方案一:Intel的CPU与Intel主板
 */
public class Schema1 implements AbstractFactory{

	@Override
	public CPUApi createCPUApi() {
		return new IntelCPU(1156);
	}

	@Override
	public MainboardApi createMainboardApi() {
		return new IntelMainboard(1156);
	}
}
/**
 * 装机方案二:AMD的CPU与AMD的主板
 */
class Schema2 implements AbstractFactory{

	@Override
	public CPUApi createCPUApi() {
		return new AMDCPU(939);
	}

	@Override
	public MainboardApi createMainboardApi() {
		return new AMDMainboard(939);
	}
}

  • 装机工程师

/**
 * 装机工程师,不知道具体实现,只根据客户要求组装电脑
 */
class ComputerEngineer{
	private CPUApi cpu=null;
	private MainboardApi mainboard=null;
	//根据方案组装电脑
	public void makeComputer(AbstractFactory schema){
		//使用抽象工厂获取相应的接口对象
		this.cpu=schema.createCPUApi();
		this.mainboard=schema.createMainboardApi();
		//测试下..
		cpu.calculate();
		mainboard.installCPU();
	}
}

  • 客户端
public class Client {
	public static void main(String[] args) {
		//创建工程师对象
		ComputerEngineer engineer=new ComputerEngineer();
		//客户选择并创建想要的装机方案
		AbstractFactory schema=new Schema1();
		engineer.makeComputer(schema);
	}
}

定义可扩展的工厂

相对灵活但不太安全的改进方式:在抽象工厂中不需定义那么多方法,只定义一个方法,给这个方法设置一个参数,通过这个参数判断具体创建什么产品簇对象;这个方法的返回值就不能是具体某个产品类型了,可以是所有产品簇都实现的接口,也可以直接用Object类型

//抽象工厂修改
public interface AbstractFactory {
	public Object createProduct(int type);
}
//装机方案修改
public class Schema1 implements AbstractFactory{
	@Override
	public Object createProduct(int type){
		Object result=null;
		if(type==1){
			result=new IntelCPU(1156);
		}else if (type==2){
			result=new IntelMainboard(1156);
		}
		return result;
	}
}
//装机工程师修改
public class ComputerEngineer{
	private CPUApi cpu=null;
	private MainboardApi mainboard=null;
	public void makeComputer(AbstractFactory schema){
		//强制转换成接口对象,如果不匹配则会报错,所以不安全
		this.cpu=(CPUApi)schema.createProduct(1);
		this.mainboard=(MainboardApi)schema.createProduct(2);
		cpu.calculate();
		mainboard.installCPU();
	}
}

此时,如果要加入一个新的产品-内存,当然可以提供一个新的装机方案来使用它,这样已有的代码就不需要变化了

理解抽象工厂模式

  • 抽象工厂的本质:选择产品簇的实现
  • 抽象工厂的功能

为一系列相关对象或相互依赖的对象创建一个接口。注意:接口内的方法不是任意堆砌的,而是一系列相关或相互依赖的方法,比如上面的CPU与主板,就是为组装一台电脑的相关对象

  • 使用工厂方法

AbstractFactory定义的创建产品的方法可以看成是工厂方法,而这些工厂方法的具体实现就延迟到了具体的工厂里面。也就是说使用工厂方法来实现抽象工厂

  • 切换产品簇

抽象工厂定义的是一个产品簇,这带来很大的灵活性,切换产品簇的时候,只需提供不同的抽象工厂实现就可以了,也就是说现在是以产品簇作为一个整体被切换

  • 何时选用抽象工厂模式?
    • 系统中有多个产品族,而系统一次只可能消费其中一族产品。【产品族概念:位于不同产品等级结构中,功能相关联的产品组成的家族。比如AMD的CPU和ADM芯片的主板,组成一个家族。Intel的CPU和Intel芯片的主板,又组成另一个家族】
    • 同属于同一个产品族的产品一起使用。
  • 优点:
    • 分离接口和实现
    • 使得切换产品簇变的容易
  • 缺点:
    • 不太容易扩展新产品。前面提到的扩展工厂方式可以但不够安全,所以需根据实际情况权衡。
    • 容易造成类层次复杂




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值