提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
PS: 最后一个涉及工厂的模式了,简单工厂模式 和工厂方法模式 请点此链接前往。这三个模式实在好像。
生活中常见的一个例子,我们在组装电脑的时候,通常要选择一系列配件,比如CPU,硬盘,内存,主板等等,这里为了方便,我们只拿CPU和主板做例子。
事实上,CPU有一系列品牌,主频,针脚数目等;主板也是一样。对于装机人员来说,他只知道组装一台电脑,至于具体用什么配件,由客户说了算。虽然由客户说了算,但是仍然存在一个前提,那就是要考虑兼容性,用户选择的CPU要能够和主板相配,如果CPU针脚数和主板提供的CPU插口不兼容,那么也就无法组装成一台电脑。
接下来,我们模拟这一过程:
对于客户而言,选择自己需要的CPU和主板,然后告诉装机人员自己的选择。
对于装机人员而言,只是知道CPU和主板的接口,不知道具体实现,那么可以使用简单工厂或者工厂方法模式来实现。为了方便,我们使用简单工厂模式。
/**
* CPU 接口
* Created by jerry on 16-4-22.
*/
public interface CPUApi {
/**
* cpu具有计算功能
*/
public void calculate();
}
/**
* 主板接口
* Created by jerry on 16-4-22.
*/
public interface MainBoardApi {
/**
* 主板具有安装CPU的功能
*/
public void installCPU();
}
/**
* Intel 的 CPU
* Created by jerry on 16-4-22.
*/
public class IntelCPU implements CPUApi {
/**
* CPU 的针脚数
*/
private int pins;
public IntelCPU(int pins) {
this.pins = pins;
}
@Override
public void calculate() {
System.out.println("Intel CPU 针脚数:" + pins);
}
}
/**
* AMD 的 CPU
* Created by jerry on 16-4-22.
*/
public class AMDCPU implements CPUApi {
/**
* CPU 的针脚数
*/
private int pins;
public AMDCPU(int pins) {
this.pins = pins;
}
@Override
public void calculate() {
System.out.println("AMD CPU 针脚数:" + pins);
}
}
/**
* 技嘉主板
* Created by jerry on 16-4-22.
*/
public class GAMainBoard implements MainBoardApi {
/**
* CPU 插槽孔数
*/
private int cpuHoles;
public GAMainBoard(int cpuHoles) {
this.cpuHoles = cpuHoles;
}
@Override
public void installCPU() {
System.out.println("技嘉主板CPU插孔数:" + cpuHoles);
}
}
/**
* 微星主板
* Created by jerry on 16-4-22.
*/
public class MSIMainBoard implements MainBoardApi {
/**
* CPU 插槽孔数
*/
private int cpuHoles;
public MSIMainBoard(int cpuHoles) {
this.cpuHoles = cpuHoles;
}
@Override
public void installCPU() {
System.out.println("微星主板CPU插孔数:" + cpuHoles);
}
}
创建CPU和主板的工厂类
/**
* 创建CPU的简单工厂
* Created by jerry on 16-4-22.
*/
public class CPUFactory {
public static CPUApi createCPUApi(int type) {
CPUApi cpu = null;
if (type == 1) {
cpu = new IntelCPU(1156);
} else if (type == 2) {
cpu = new AMDCPU(939);
}
return cpu;
}
}
/**
* 创建主板的简单工厂
* Created by jerry on 16-4-22.
*/
public class MainBoardFactory {
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;
}
}
/**
* 装机人员类,接受用户需求,组装计算机
* Created by jerry on 16-4-22.
*/
public class ComputerEngineer {
private CPUApi cpu;
private MainBoardApi mainBoard;
public void makeComputer(int cpuType, int mainBoardType) {
//组装计算机
initComponent(cpuType, mainBoardType);
// 测试计算机
// ...
}
/**
* 组装计算机
* @param cpuType 客户选择的cpu类型
* @param mainBoardType 客户选择的主板类型
*/
private void initComponent(int cpuType, int mainBoardType) {
this.cpu = CPUFactory.createCPUApi(cpuType);
this.mainBoard = MainBoardFactory.createMainBoardApi(mainBoardType);
//运行配件是否可以用
this.cpu.calculate();
this.mainBoard.installCPU();
}
}
客户调用:
/**
* 客户端调用,模拟客户
* Created by jerry on 16-4-22.
*/
public class Client {
public static void main(String[] args) {
// 告诉装机人员自己的需求
ComputerEngineer engineer = new ComputerEngineer();
engineer.makeComputer(1,1);
}
}
当我们选择Intel的CPU和技嘉的主板时,运行如下:
Intel CPU 针脚数:1156
技嘉主板CPU插孔数:1156
似乎运行良好,但当我们选择Intel的CPU和微星的主板时,运行如下:
Intel CPU 针脚数:1156
微星主板CPU插孔数:939
发现CPU和主板的接口是不合的,也就是说,他们根本不能组装在一起的。
所以当我们需要创建一系列相关的对象时,这时我们就需要抽象工厂模式。
而简单工厂和工厂方法模式中,创建的对象则可以是任意的,没有任何限制。还记得吗,在简单工厂模式的介绍中,我们又称简单工厂是 万能工厂
。
新建抽象工厂接口,虽然有抽象二字,但是通常情况下,抽象工厂是一个接口
/**
* 抽象工厂接口,虽然它叫抽象工厂,但通常其不是一个抽象类,而是一个接口
* Created by jerry on 16-4-22.
*/
public interface AbstractFactory {
public CPUApi createCPUApi();
public MainBoardApi createMainBoardApi();
}
只要实现此接口,就可以限制子类之间的关系:
/**
* 装机方案一: 使用Intel 的CPU 和 技嘉的主板
* Created by jerry on 16-4-22.
*/
public class Schema1 implements AbstractFactory {
@Override
public CPUApi createCPUApi() {
return new IntelCPU(1156);
}
@Override
public MainBoardApi createMainBoardApi() {
return new GAMainBoard(1156);
}
}
/**
* 装机方案二: 使用AMD 的CPU 和 微星的主板
* Created by jerry on 16-4-22.
*/
public class Schema2 implements AbstractFactory {
@Override
public CPUApi createCPUApi() {
return new AMDCPU(939);
}
@Override
public MainBoardApi createMainBoardApi() {
return new MSIMainBoard(939);
}
}
此时告诉装机人员的是一套装机方案了,而不是任意类型,从而保证了兼容性
/**
* 装机人员类,接受装机方案,组装计算机
* Created by jerry on 16-4-22.
*/
public class ComputerEnginee2 {
private CPUApi cpu;
private MainBoardApi mainBoard;
public void makeComputer(AbstractFactory schema) {
//组装计算机
initComponent(schema);
// 测试计算机
// ...
}
/**
* 组装计算机
* @param cpuType 客户选择的cpu类型
* @param mainBoardType 客户选择的主板类型
*/
private void initComponent(AbstractFactory schema) {
this.cpu = schema.createCPUApi();
this.mainBoard = schema.createMainBoardApi();
//运行配件是否可以用
this.cpu.calculate();
this.mainBoard.installCPU();
}
}
客户端调用时,用户传入一套装机方案:
/**
* 客户端调用,模拟客户
* Created by jerry on 16-4-22.
*/
public class Client {
public static void main(String[] args) {
// 告诉装机人员自己的需求
/* ComputerEngineer engineer = new ComputerEngineer();
engineer.makeComputer(1,2);*/
ComputerEnginee2 enginee2 = new ComputerEnginee2();
AbstractFactory schema = new Schema1();
enginee2.makeComputer(schema);
}
}
由于抽象工厂定义的一系列对象通常是相关或者相互依赖的,这些产品对象就构成了一个产品簇,也就是定义了一个产品簇。这就带来非常大的灵活性,切换一个产品簇的时候,只要提供不同的抽象工厂实现就可以了,也就是说现在是以产品簇作为一个整体被切换了。
何时使用抽象工厂模式:
Github: https://github.com/jerry-sc/designPattern
Reference:《研磨设计模式》