介绍
抽象工厂可以看成是由于产品类又被抽象的结果,在工厂模式中工厂能生产一种产品类(产品簇)的一系列产品,但是如果每一个产品类又有着进一步的分类便需要进一步抽象,例如工厂能生产多种程序员,但是每个程序员又有了程序员主体和程序员细节的划分,便需要抽象工厂了
具体实现
角色划分
ProductApi:生产者API,用于定义生产者的行为规范,即抽象接口
ConcreteProduct:生产者角色,具体已经实现接口的生产者
ProductFactory:抽象的工厂,创建不同产品类的工厂(字节类和阿里类)
ConcreteFactory:具体的工厂,负责具体的某个产品类的产品的加工(程序员1和程序员2)
Client:消费者,需要使用具体的某个生产者
代码实现
ProductApi类
public interface ProgrammerDetail {
void detailLife();
}
public interface Programmer {
void dayLife();
}
ProductRole
public class Programmer1 implements Programmer{
@Override
public void dayLife() {
System.out.println("程序员1:起床-敲代码-吃饭-逛街-睡觉");
}
}
public class Programmer2 implements Programmer{
@Override
public void dayLife() {
System.out.println("程序员2:起床-敲代码-吃饭-逛街-睡觉");
}
}
public class Programmer1Detail implements ProgrammerDetail {
@Override
public void detailLife() {
System.out.println("逛街是自己逛街");
}
}
public class Programmer2Detail implements ProgrammerDetail {
@Override
public void detailLife() {
System.out.println("逛街是陪女朋友逛街");
}
}
ProductFactory
public abstract class ProgrammerFactory {
public abstract Programmer getProgrammer();
public abstract ProgrammerDetail getDetail();
}
ConcreteFactory(具体的工厂)
public class Programmer1Factory extends ProgrammerFactory {
@Override
public Programmer getProgrammer() {
return new Programmer1();
}
@Override
public ProgrammerDetail getDetail() {
return new Programmer1Detail();
}
}
public class Programmer2Factory extends ProgrammerFactory {
@Override
public Programmer getProgrammer() {
return new Programmer2();
}
@Override
public ProgrammerDetail getDetail() {
return new Programmer2Detail();
}
}
Client(用于测试的消费者1)
public class Client1 {
public static void main(String[] args) {
ProgrammerFactory programmerFactory = new Programmer2Factory();
Programmer programmer = programmerFactory.getProgrammer();
ProgrammerDetail detail = programmerFactory.getDetail();
programmer.dayLife();
detail.detailLife();
}
}
事实上我这个例子也举的不太友好,下面再拿个《研磨设计模式》中的例子解释下
有两个产品类订单主体和订单细节,两个产品簇数据库存储和Xml存储
扩展产品簇时很容易比如再加个本地缓存存储,直接写个CacheFactory实现DAOFactory接口,然后完善两个方法
扩展产品类就不容易了,比如再加个订单简介,那么所有的子类factory都需要实现一个新方法
优缺点
优点
使得切换产品簇变得容易
因为一个具体的工厂实现代表的是一个产品簇,比如上面例子的程序员中程序员1代表方案一:程序员1的日常生活和细节生活,如果要切换成为程序员2,那就变成了方案二:程序员2的日常生活和细节生活
客户端选用不同的工厂实现,就相当于是在切换不同的产品簇
缺点
切换产品簇容易,但是扩展产品簇下的新产品便不容易,比如再扩展一个ProgrammerPrivacy(程序员隐私)接口,那么抽象工厂需要增加一个抽象方法返回该类,那么抽象类的所有子类都需要多加一个方法
在使用抽象工厂模式的时候,如果需要选择的层次过多,那么会造成整个类层次变得复杂,也就是产品簇上还有产品簇,有点套娃的意思,层次多了非常容易出错
讨论工厂方法与抽象工厂
此处可先看上一篇博客工厂模式的JDK源码分析部分工厂模式
笔者关于这里的区别确实是思考了很久不得解,知道看了JDK源码的设计模式才恍然大悟(JDK才是永远的神)
在Calendar中可以看出工厂模式的工厂也能有多个方法,但是这些方法返回值大多是一个对象,即使不是大多目的也是为了更好的创建那一个对象(比如Calendar中有大量返回内部类Builder的方法,Builder也是用来更好的创建Calendar的),所以工厂类的职责自始至终都是专注于创建一个对象;然而我们来看抽象工厂却不是这样,抽象工厂的每个方法都可以是不同的对象,也就是说抽象工厂类的职责是创建多个对象。如果说工厂模式是用多种方法来完善一个产品类,那么抽象工厂使用多种方法创建多个产品来完善一个产品簇
理解了这个,不难想到,我们还可以将抽象工厂与工厂方法结合使用,将抽象工厂的一个子类工厂当成工厂模式的抽象工厂再抛给子类去实现,比如将上文的RdbDaoFactory做成抽象的,写两个子类RdbOrderMainFactory和RdbOrderDetailFactory,两个子类专注于一个产品的创建。当然这样做像套娃一样,系统复杂度会提高很多,一定要结合业务,且行且珍惜
注意点
当抽象工厂模式只需要加工一个产品,即只有一个方法,那么事实上就退化成了工厂模式而已
选用时机
如果一个系统要由多个产品系列中的一个来配置的时候。换句话说,就是可以动态地切换产品簇的时候使用
总的来说抽象工厂更重视有着多个产品簇的划分,每个产品簇都有着自己的多个产品