二、创建型模式:抽象工厂模式(Abstract Factory)

时间:2022-09-08 20:09:56
        追MM少不了请吃饭了,麦当劳的套餐和肯德基的套餐都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说“两个B套餐”就行了。麦当劳和肯德基就是B套餐的Abstract Factory, B套餐里含有汉堡, 鸡翅和饮料. 麦当劳或肯德基会根据B套餐的规格, 让汉堡Factory, 鸡翅Factory, 饮料Factory分别生产对应B套餐的材料.


定义  
        有称作“工具箱”模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。



使用场景

        一个系列要独立于它的产品的创建、组合和表示时。
        一个系统要由多个产品系列中的一个来配置时。
        当要强调一系列相关的产品对象的设计以便进行联合使用时。
        当要提供一个产品类库,而只要显示它们的接口而不是实现时。
        简单的说就是适用于客户端中经常需要切换配置(交换产品系列)时,客户端通过抽象接口来操纵实例,具体的类名不会出现在客户端中。



优缺点分析

  优点 缺点
简单工厂模式
  • 分离了客户端和后台逻辑,使得客户端无需关心后台的实现,去除了客户端与具体产品的依赖,增强了移植性能。
  • 实现简单,易于操作。
  • 违背了开放-封闭原则
  • 添加新产品时比较麻烦
工厂方法模式
  • 是简单工厂模式的升级
  • 易于添加新产品
  • 后台模块契合了开放-封闭原则
  • 新产品的添加带来了大量新的类的创建,增加了工作量
  • 客户端部分仍然违反开放-封闭原则,只是后台判断逻辑挪到了前台
抽象工厂模式
  • 分离了具体的类,工厂封装了创建产品对象的责任和过程,将客户端和类的实现分离,客户端通过抽象接口操纵实例
  • 易于交换产品系列,一个具体的工厂类在一个应用中仅在初始化时出现一次,改变一个应用的具体工厂变得容易
  • 有利于产品的一致性,一个系列中的产品对象被设计成一起工作时,一个应用一次只能使用同一系列中的对象
  • 难以支持新种类的产品,抽象工厂接口确定了可以被创建的产品集合。新种类产品加入需要扩展抽象工厂接口,这就涉及到了接口本身和所有实现类的改变



角色及其职责
抽象工厂(Abstract Factory)角色:担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的。
具体工厂(Concrete Factory)角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。
抽象产品(Abstract Product)角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。
具体产品(Concrete Product)角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。



抽象工厂模式UML图 二、创建型模式:抽象工厂模式(Abstract Factory)

应用场景及代码分析
       程序员小明使用工厂方法模式对面包店进行了一番改造,效果显著,加入新的面包时变得容易了,可是,小明的生意做的越来越大,并不满足只卖面包了,他想在自己的店里面加入自己喜欢吃的披萨,于是按照他开始了编码的道路
       首先将我们的面包师和面包写出来:

//面包师,作为父类
public class BreadMaker {
//生产面包
public void getBread(){
//等待孩子们生产出来
}
}

//奶油面包
public class ButterBread extends BreadMaker{
// 覆盖父类方法
@Override
public void getBread() {
// TODO Auto-generated method stub
super.getBread();
System.out.println("烤出了奶油面包");
}
}

//巧克力面包
public class ChocolateBread extends BreadMaker{
// 覆盖父类方法
@Override
public void getBread() {
// TODO Auto-generated method stub
super.getBread();
System.out.println("烤出了巧克力面包");
}
}

//香蕉面包
public class BananaBread extends BreadMaker{
// 覆盖父类方法
@Override
public void getBread() {
// TODO Auto-generated method stub
super.getBread();
System.out.println("烤出了香蕉面包");
}
}



同样,类似于面包师和面包,也创建出了披萨师和各种披萨
//披萨师 各种披萨的父类
public class PizzaMaker {
//制作披萨
public void GetPizza(){

}
}

//奶油披萨
public class ButterPizza extends PizzaMaker {

@Override
public void GetPizza() {
// TODO Auto-generated method stub
super.GetPizza();
System.out.println("制作出了奶油披萨");
}
}

//巧克力披萨
public class ChocolatePizza extends PizzaMaker {

@Override
public void GetPizza() {
// TODO Auto-generated method stub
super.GetPizza();
System.out.println("制作出了巧克力披萨");
}
}

//香蕉披萨
public class BananaPizza extends PizzaMaker {

@Override
public void GetPizza() {
// TODO Auto-generated method stub
super.GetPizza();
System.out.println("制作出了香蕉披萨");
}
}


写到这里,按照之前工厂方法模式的方法,还需要添加新的工厂接口和3个披萨实体类对应的工厂实体类,小明突然发现这样做的成本太大了,回头想了想,原来披萨和面包的制作方法都是相似的嘛,完全可以放在一起制作啊,对于顾客来说,他们并不关心面包和披萨在哪里做出来的,关心的是面包和披萨的直接、快速取得。于是在同一个工厂里加入了披萨工厂。
//工厂接口
public interface IFactory {
BreadMaker createBread();
//增加了返回披萨实例的接口方法
PizzaMaker createPizzer();
}

//奶油面包和奶油披萨的工厂方法实现
public class ButterBreadFactory implements IFactory{

@Override
public BreadMaker createBread() {
//返回奶油面包实例
return new ButterBread();
}

@Override
public PizzaMaker createPizzer() {
// 返回奶油披萨实例
return new ButterPizza();
}
}

//巧克力面包和巧克力披萨的工厂方法实现
public class ChocolateBreadFactory implements IFactory{
@Override
public BreadMaker createBread() {
//返回巧克力面包实例
return new ButterBread();
}

@Override
public PizzaMaker createPizzer() {
// 返回巧克力披萨实例
return null;
}
}


//香蕉面包和香蕉披萨的工厂方法实现
public class BananaBreadFactory implements IFactory{
@Override
public BreadMaker createBread() {
//返回香蕉面包实例
return new ButterBread();
}

@Override
public PizzaMaker createPizzer() {
//返回香蕉披萨实例
return null;
}
}


现在小明又开始重新开张了:
//抽象工厂模式测试
public class AbstractFactoryTest {

public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("小明面包披萨店开始营业!");
BreadMaker breadMaker = null;
PizzaMaker pizzaMaker = null;
IFactory breadFactory = null;
System.out.println("顾客要一个奶油面包");
//根据需要实例化接口
breadFactory = new ButterBreadFactory();
breadMaker =breadFactory.createBread();
breadMaker.getBread();

System.out.println("顾客要一个奶油披萨");
pizzaMaker =breadFactory.createPizzer();
pizzaMaker.GetPizza();
}
}


输出结果:
小明面包披萨店开始营业!
顾客要一个奶油面包
烤出了奶油面包
顾客要一个奶油披萨
制作出了奶油披萨