目录
场景
我要组装电脑,但是我不会,我要找一个装机师傅来帮我做,我只需要提供硬件的型号就行了。
假设我现在需要提供CPU和主板信息给装机师傅,那么创建CPU和主板的Api,并通过实现类来实现他们
CPUApi
package day06抽象工厂模式;
/**
* CPU
*/
public interface CPUApi {
/**
* cpu具有计算功能
*/
void calculate();
}
ZhuApi
package day06抽象工厂模式;
/**
* 主板
*/
public interface ZhuApi {
/**
* 主板具有能安装CPU的功能
*/
void installCPU();
}
CPU两个实现类,一个是Inter的,一个是AMD的,构造方法中传入CPU的针脚数
package day06抽象工厂模式.Impl;
import day06抽象工厂模式.CPUApi;
public class InterCPUImpl implements CPUApi {
/**
* CPU针脚数
*/
private int pins = 0;
/**
* 构造方法,传入CPU的针脚数目
* @param pins CPU的针脚数目
*/
public InterCPUImpl(int pins){
this.pins = pins;
}
@Override
public void calculate() {
System.out.println("Inter的cpu,针脚数 = " + pins);
}
}
package day06抽象工厂模式.Impl;
import day06抽象工厂模式.CPUApi;
public class AMDCPUImpl implements CPUApi {
/**
* CPU针脚数
*/
private int pins = 0;
/**
* 构造方法,传入CPU的针脚数目
* @param pins CPU的针脚数目
*/
public AMDCPUImpl(int pins){
this.pins = pins;
}
@Override
public void calculate() {
System.out.println("AMD的cpu,针脚数 = " + pins);
}
}
主板也有两个实现,一个是技嘉一个是微星,构造方法中传入CPU插槽的孔数
package day06抽象工厂模式.Impl;
import day06抽象工厂模式.ZhuApi;
/**
* 技嘉的主板
*/
public class JjZhuImpl implements ZhuApi {
/**
* CPU插槽的孔数
*/
private int cpuHoles = 0;
/**
* 构造方法,传入CPU插槽的孔数
* @param cpuHoles CPU插槽的孔数
*/
public JjZhuImpl(int cpuHoles){
this.cpuHoles = cpuHoles;
}
@Override
public void installCPU() {
System.out.println("现在是技嘉主板,cpu孔数为" + cpuHoles);
}
}
package day06抽象工厂模式.Impl;
import day06抽象工厂模式.ZhuApi;
/**
* 技嘉的主板
*/
public class WxZhuImpl implements ZhuApi {
/**
* CPU插槽的孔数
*/
private int cpuHoles = 0;
/**
* 构造方法,传入CPU插槽的孔数
* @param cpuHoles CPU插槽的孔数
*/
public WxZhuImpl(int cpuHoles){
this.cpuHoles = cpuHoles;
}
@Override
public void installCPU() {
System.out.println("现在是微星主板,cpu孔数为" + cpuHoles);
}
}
创建CPU和主板的工厂
package day06抽象工厂模式.factory;
import day06抽象工厂模式.CPUApi;
import day06抽象工厂模式.Impl.AMDCPUImpl;
import day06抽象工厂模式.Impl.InterCPUImpl;
/**
* 创建CPU的简单工厂
*/
public class CPUFactory {
static CPUApi createApi(int type){
CPUApi cpu = null;
// 根据参数来选择并创建相应的CPU对象
if (type == 1){
cpu = new InterCPUImpl(1156);
}else if (type == 2){
cpu = new AMDCPUImpl(939);
}
return cpu;
}
}
package day06抽象工厂模式.factory;
import day06抽象工厂模式.Impl.JjZhuImpl;
import day06抽象工厂模式.Impl.WxZhuImpl;
import day06抽象工厂模式.ZhuApi;
/**
* 创建主板的简单工厂
*/
public class ZhuFactory {
static ZhuApi createApi(int type){
ZhuApi zhuban = null;
// 根据参数来选择并创建相应的主板对象
if (type == 1){
zhuban = new JjZhuImpl(1156);
}else if (type == 2){
zhuban = new WxZhuImpl(939);
}
return zhuban;
}
}
装机工程师实现的代码
package day06抽象工厂模式;
import day06抽象工厂模式.factory.CPUFactory;
import day06抽象工厂模式.factory.ZhuFactory;
/**
* 装机工程师实现
*/
public class ComputerEngineer {
/**
* 1.定义组装机器需要的CPU
*/
private CPUApi cpu = null;
/**
* 2.定义组装机器需要的主板
*/
private ZhuApi zhuban = null;
/**
* 3.装机过程
*/
private void makeComputer(int cpuType,int zhubanType){
// 1.首先准备好装机所需要的配件
prepareHardwares(cpuType,zhubanType);
// 2.组装机器
// 3.测试机器
// 4.交付客户
}
private void prepareHardwares(int cpuType,int zhubanType){
// 工程师不知道怎么创建,那就用到了之前创建的CPU和主板的工厂
this.cpu = CPUFactory.createApi(cpuType);
this.zhuban = ZhuFactory.createApi(zhubanType);
// 测试一下配件好用不
this.cpu.calculate();
this.zhuban.installCPU();
}
}
客户端通过装机工程师来组装电脑,并告诉工程师自己选择的配件
package day06抽象工厂模式;
/**
* 客户端通过装机工程师来组装电脑,并告诉工程师自己选择的配件
*/
public class Client {
public static void main(String[] args) {
// 创建装机工程师对象
ComputerEngineer engineer = new ComputerEngineer();
// 告诉工程师自己选择的配件,让装机工程师组装电脑
engineer.makeComputer(1,1); // Inter的CPU,技嘉的主板
}
}
有何问题
CPU和主板是有关系的,CPU针脚数要与主板插槽对应,当我们入参传1,2时,也能装机,就是因为没有对关联关系进行约束
解决方案
抽象工厂
定义
解决思路
与简单工厂和工厂方法模式的不同
简单工厂和工厂方法关注的是单个产品的创建。
这里要解决的是创建一系列的产品对象并且这些对象都是构建新对象的重要组成部分并且相互之间是有约束关系的。
重写示例
思路
实现
既然用到抽象工厂,那么之前创建CPU和主板的简单工厂就不要了,也就是factory里面的文件
CPU和主板的Api和Impl保留.
新增抽象工厂定义
package day06抽象工厂模式.factory;
import day06抽象工厂模式.CPUApi;
import day06抽象工厂模式.ZhuApi;
/**
* 方案A:因特尔的CPU和技嘉的主板
*/
public interface AbstractFactory{
/**
* 创建CPU的对象
* @return
*/
public ZhuApi createZhuApi();
/**
* 创建主板的对象
* @return
*/
public CPUApi createCPUApi();
}
抽象工厂的实现,它所代表的就是我给用户出方案,用户来选择就行了
PlanA 方案A
package day06抽象工厂模式.factory;
import day06抽象工厂模式.CPUApi;
import day06抽象工厂模式.Impl.InterCPUImpl;
import day06抽象工厂模式.Impl.JjZhuImpl;
import day06抽象工厂模式.ZhuApi;
public class PlanA implements AbstractFactory{
@Override
public CPUApi createCPUApi() {
return new InterCPUImpl(1156);
}
@Override
public ZhuApi createZhuApi() {
return new JjZhuImpl(1156);
}
}
PlanB 方案B
package day06抽象工厂模式.factory;
import day06抽象工厂模式.CPUApi;
import day06抽象工厂模式.Impl.AMDCPUImpl;
import day06抽象工厂模式.Impl.InterCPUImpl;
import day06抽象工厂模式.Impl.JjZhuImpl;
import day06抽象工厂模式.Impl.WxZhuImpl;
import day06抽象工厂模式.ZhuApi;
/**
* 方案B:AMD的CPU和微星的主板
*/
public class PlanB implements AbstractFactory{
@Override
public CPUApi createCPUApi() {
return new AMDCPUImpl(939);
}
@Override
public ZhuApi createZhuApi() {
return new WxZhuImpl(939);
}
}
装机工程师的实现
与前面不同的是:从客户端不再传入选择的CPU和主板,而是直接传入客户选择并创建好的装机方案对象
package day06抽象工厂模式;
import day06抽象工厂模式.factory.AbstractFactory;
/**
* 装机工程师实现
*/
public class ComputerEngineer {
/**
* 1.定义组装机器需要的CPU
*/
private CPUApi cpu = null;
/**
* 2.定义组装机器需要的主板
*/
private ZhuApi zhuban = null;
/**
* 3.装机过程
*/
public void makeComputer(AbstractFactory plan){
// 1.首先准备好装机所需要的配件
prepareHardwares(plan);
// 2.组装机器
// 3.测试机器
// 4.交付客户
}
/**
* 准备装机所需要的配件
* @param plan 客户选择的装机方案
*/
private void prepareHardwares(AbstractFactory plan){
// 工程师不知道怎么创建,那就用到了之前创建的CPU和主板的工厂
this.cpu = plan.createCPUApi();
this.zhuban = plan.createZhuApi();
// 测试一下配件好用不
this.cpu.calculate();
this.zhuban.installCPU();
}
}
客户端实现
package day06抽象工厂模式;
import day06抽象工厂模式.factory.PlanA;
import day06抽象工厂模式.factory.PlanB;
/**
* 客户端通过装机工程师来组装电脑,并告诉工程师自己选择的配件
*/
public class Client {
public static void main(String[] args) {
// 创建装机工程师对象
ComputerEngineer engineer = new ComputerEngineer();
// 客户选择并创建需要使用的装机方案
PlanA planA = new PlanA();
PlanB planB = new PlanB();
// 告诉工程师自己选择的装机方案,让装机工程师组装电脑
engineer.makeComputer(planB);
}
}
模式讲解
抽象工厂模式的功能:为一系列相关对象或相互依赖的对象创建一个接口。
AbstractFactory定义了创建产品所需要的接口,具体的实现是在PlanA/B里面选择更多具体的实现。所以AbstractFactory定义的创建产品的方法可以看作是工厂方法,而这些工厂方法的具体实现就延迟到了具体的工厂里面,也就是说使用工厂方法来实现抽象方法。
高级用法
新建一个抽象工厂,只提供生产商品这一种方法,定义一下类型type,这个type只负责是生产CPU还是主板,不关心什么型号,因为不知道返回的是CPU还是主板,所以类型定义为Object
package day06抽象工厂模式.myFactory;
public interface MyAbstractFactory {
/**
* 一个通用的创建产品对象的方法 type表示要创建CPU还是创建主板,不再进一步表示创建什么型号
*/
public Object createProduct(int type);
}
在实现类中也就是方案里面判断type
planA
package day06抽象工厂模式.myFactory;
import day06抽象工厂模式.Impl.InterCPUImpl;
import day06抽象工厂模式.Impl.JjZhuImpl;
public class planA implements MyAbstractFactory{
@Override
public Object createProduct(int type) {
Object obj = null;
// type = 1 创建cpu
// type = 2 创建主板
if (type == 1){
obj = new InterCPUImpl(1156);
}else if(type == 2){
obj = new JjZhuImpl(1156);
}
return obj;
}
}
planB
package day06抽象工厂模式.myFactory;
import day06抽象工厂模式.Impl.AMDCPUImpl;
import day06抽象工厂模式.Impl.InterCPUImpl;
import day06抽象工厂模式.Impl.JjZhuImpl;
import day06抽象工厂模式.Impl.WxZhuImpl;
public class planB implements MyAbstractFactory{
@Override
public Object createProduct(int type) {
Object obj = null;
// type = 1 创建cpu
// type = 2 创建主板
if (type == 1){
obj = new AMDCPUImpl(939);
}else if(type == 2){
obj = new WxZhuImpl(939);
}
return obj;
}
}
装机工程师的实现过程
package day06抽象工厂模式.myFactory;
import day06抽象工厂模式.CPUApi;
import day06抽象工厂模式.MemoryApi;
import day06抽象工厂模式.ZhuApi;
public class MyConputerEngineer {
/**
* 1.定义组装机器需要的CPU
*/
private CPUApi cpu = null;
/**
* 2.定义组装机器需要的主板
*/
private ZhuApi zhuban = null;
/**
* 3.定义组装电脑的内存
*/
// private MemoryApi memory = null;
/**
* 4.装机过程
*/
public void makeComputer(MyAbstractFactory plan){
// 1.首先准备好装机所需要的配件
prepareHardwares(plan);
// 2.组装机器
// 3.测试机器
// 4.交付客户
}
/**
* 准备装机所需要的配件
* @param plan 客户选择的装机方案
*/
private void prepareHardwares(MyAbstractFactory plan){
/**
* 这里因为返回的是Object,所以要进行强转
*/
this.cpu = (CPUApi) plan.createProduct(1);
this.zhuban = (ZhuApi) plan.createProduct(2);
// this.memory = (MemoryApi) plan.createProduct(3);
// 测试一下配件好用不
this.cpu.calculate();
this.zhuban.installCPU();
// if (memory != null){
// this.memory.cacheData();
// }
}
}
在这里请明确:工程师是负责创建CPU和主板的,我们在抽象工厂MyAbstractFactory中说明了type = 1 是创建CPU,type=2是创建主板,所以plan.createProduct()负责创建什么。
Client客户端实现
package day06抽象工厂模式.myFactory;
public class Client {
public static void main(String[] args) {
MyConputerEngineer myConputerEngineer = new MyConputerEngineer();
planA a = new planA();
// planB b = new planB();
// planC c = new planC();
myConputerEngineer.makeComputer(a);
}
}
总结一下:我们首先定义了一个抽象工厂,里面只有一个方法就是创建商品,怎么创建呢?根据type的类型创建是CPU还是主板,我们又定义了两个方案planA/B,对应着不同型号的CPU和主板。我们在装机师傅这个实现过程中,通过调用抽象工厂中的方法,确定我们要创建两个东西,一个是CPU,另一个是主板。最后我们在客户端使用的时候,首先创建工程师,然后选择方案 ,工程师开始装机。
plan方案定义了type类型不同的两个值创建什么样的CPU跟主板
(MyConputerEngineer)装机师傅这个实现过程中,确定创建什么?也就是调用了两次方案中的方法,只不过传入的type不同,区分创建的是CPU还是主板。
根据传入不同的值来调用不同的实现Impl
好处:易于扩展。比如现在我想加一个安装的东西,内存;
我只需要定义内存接口,内存实现,然后planC,工程师实现装机方法中增加内存,最后客户端创建方案时调用planC就行了。代码如下
内存接口
package day06抽象工厂模式;
/**
* 内存
*/
public interface MemoryApi {
/**
* 内存具有缓存数据的能力
*/
void cacheData();
}
内存实现
package day06抽象工厂模式.Impl;
import day06抽象工厂模式.MemoryApi;
public class HyMemory implements MemoryApi {
@Override
public void cacheData() {
System.out.println("现在正在使用现代内存");
}
}
planC方案 定义cpuAMD1234 主板微星1234 并且装机的时候还要装内存
package day06抽象工厂模式.myFactory;
import day06抽象工厂模式.Impl.AMDCPUImpl;
import day06抽象工厂模式.Impl.HyMemory;
import day06抽象工厂模式.Impl.WxZhuImpl;
public class planC implements MyAbstractFactory{
@Override
public Object createProduct(int type) {
Object obj = null;
// type = 1 创建cpu
// type = 2 创建主板
if (type == 1){
obj = new AMDCPUImpl(1234);
}else if(type == 2){
obj = new WxZhuImpl(1234);
}else if(type == 3){
obj = new HyMemory();
}
return obj;
}
}
工程师装机实现过程
package day06抽象工厂模式.myFactory;
import day06抽象工厂模式.CPUApi;
import day06抽象工厂模式.MemoryApi;
import day06抽象工厂模式.ZhuApi;
public class MyConputerEngineer {
/**
* 1.定义组装机器需要的CPU
*/
private CPUApi cpu = null;
/**
* 2.定义组装机器需要的主板
*/
private ZhuApi zhuban = null;
/**
* 3.定义组装电脑的内存
*/
private MemoryApi memory = null;
/**
* 4.装机过程
*/
public void makeComputer(MyAbstractFactory plan){
// 1.首先准备好装机所需要的配件
prepareHardwares(plan);
// 2.组装机器
// 3.测试机器
// 4.交付客户
}
/**
* 准备装机所需要的配件
* @param plan 客户选择的装机方案
*/
private void prepareHardwares(MyAbstractFactory plan){
/**
* 这里因为返回的是Object,所以要进行强转
*/
this.cpu = (CPUApi) plan.createProduct(1);
this.zhuban = (ZhuApi) plan.createProduct(2);
this.memory = (MemoryApi) plan.createProduct(3);
// 测试一下配件好用不
this.cpu.calculate();
this.zhuban.installCPU();
if (memory != null){
this.memory.cacheData();
}
}
}
客户端实现 只需要换方案就行了
package day06抽象工厂模式.myFactory;
public class Client {
public static void main(String[] args) {
// 创建工程师
MyConputerEngineer myConputerEngineer = new MyConputerEngineer();
// 选择方案
// planA a = new planA();
// planB b = new planB();
planC c = new planC();
// 装机
myConputerEngineer.makeComputer(c);
}
}
抽象工厂模式的优缺点
思考
抽象工厂模式的本质:选择产品簇的实现
何时选用
相关模式
抽象工厂与工厂方法模式
抽象工厂模式和单例模式