在原抽象工厂模式+建造者模式中添加了原型模式和适配器模式
抽象工厂模式和建造者模式结合链接:https://blog.csdn.net/qq_18625571/article/details/104416504
一、模式解析
1、原型模式
(1)概述
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。
(2)解决问题
主要解决对象的创建问题,提升创建对象的性能。每new一次就会调用一次构造函数,如果构造函数的执行时间很长,多次执行这个初始化操作就要消耗很多时间降低效率。一般在初始化的信息不发生变化的情况下,克隆是最高的方法,这即隐藏了对象创建的细节,又对性能是大大的提升。
(3)类图
(4)成员角色
Prototype(抽象原型类):声明克隆方法的接口,是所有具体原型类的公共父类,它可是抽象类也可以是接口,甚至可以是具体实现类。
ConcretePrototype(具体原型类):它实现抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。
Client(客户端):在客户类中,让一个原型对象克隆自身从而创建一个新的对象。
(5)优缺点
优点
1.如果创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率。
2.不用重新初始化对象,而是动态地获得对象运行时的状态。
缺点
1.在实现深克隆的时候可能需要比较复杂的代码。
2.需要为每一个类配备一个克隆方法,而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了“开闭原则”。
(6)使用场景
1.对象种类繁多,无法将他们整合到一个类的时候; 难以根据类生成实例时; 想解耦框架与生成的实例时。
2.如果想要让生成实例的框架不再依赖于具体的类,这时,不能指定类名来生成实例,而要事先“注册”一个“原型”实例,然后通过复制该实例来生成新的实例。
2、适配器模式
(1)概述
将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
(2)解决问题
主要作用是在新接口和老接口之间进行适配,将原本不兼容的接口融合在一起工作。
(3)类图
(4)成员角色
Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。
(5)优点
1.将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。
2.增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用。
3.灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
(6)使用场景
1.系统需要使用一些现有的类,而这些类的接口(如方法名)不符合系统的需要,甚至没有这些类的源代码。
2.想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
源码分析适配器模式的典型应用
二、结合实例
还是以卖奶茶为例
1、抽象工厂模式
(1)首先创建抽象工厂,实现Cloneable接口(衔接后面的原型模式)。也就是原材料总工厂,相当于一个大型批发市场,所有的实体工厂都开在这里。
public abstract class Factory implements Cloneable{
private String id;
protected Factory factory;
public abstract Milk CreateMilk();
public abstract Tea CreateTea();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Object clone(){
Object clone = null;
try{
clone = super.clone();
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
return clone;
}
}
(2)原材料工厂中涉及很多原材料产品种类,现在创建这些产品种类,即创建抽象产品
public interface Milk {
public String getMilk();
}
public interface Tea {
public String getTea();
}
(3)接着创建所需的具体产品。
public class PureMilk implements Milk {
PureMilk(){
System.out.print("加纯牛奶");
}
@Override
public String getMilk() {
String string="在搅拌机里加纯牛奶";
return string;
}
}
public class Yogurt implements Milk {
public Yogurt(){
System.out.print("加酸奶");
}
@Override
public String getMilk() {
String string="在搅拌机里加酸奶";
return string;
}
}
public class GreenTea implements Tea {
public GreenTea(){
System.out.print("加绿茶");
}
@Override
public String getTea() {
String string="在烤茶机里加绿茶";
return string;
}
}
public class RedTea implements Tea {
public RedTea() {
System.out.print("加红茶");
}
@Override
public String getTea() {
String string="在烤茶机里加红茶";
return string;
}
}
(4)具体原材料准备好了,则分到具体的工厂制作,所有的工厂都实现了clone()方法,可以理解为采购员去批发市场把需要的原料采购出来。
public class AFactory extends Factory {
//A厂
public Milk CreateMilk(){
Milk milk = new PureMilk();
System.out.println("(产地:A厂)");
return milk;
}
public Tea CreateTea(){
Tea tea = new GreenTea();
System.out.println("(产地:A厂)");
return tea;
}
}
public class BFactory extends Factory {
//B厂
public Milk CreateMilk(){
Milk milk = new Yogurt();
System.out.println("(产地:B厂)");
return milk;
}
public Tea CreateTea(){
Tea tea = new RedTea();
System.out.println("(产地:B厂)");
return tea;
}
}
2、原型模式
(5)创建一个类,从库中获取实体类,并把它们存储在一个 Hashtable 中。可以看做把从AB工厂批发过来的原料放在仓库里,等需要用的时候再取,就不需要每次用到原料都跑去市场购买。
public class FactoryCache {
private static Hashtable<String,Factory> shapeMap = new Hashtable<String,Factory>();
public static Factory getFactory(String factoryId){
Factory cachedFactory = shapeMap.get(factoryId);
return (Factory)cachedFactory.clone();
}
public static void loadCache(){
AFactory Afactory = new AFactory();
Afactory.setId("1");
shapeMap.put(Afactory.getId(),Afactory);
BFactory Bfactory = new BFactory();
Bfactory.setId("2");
shapeMap.put(Bfactory.getId(),Bfactory);
}
}
(6)有了原材料工厂,可以着手制作奶茶了。店长(奶茶建造者Builder)(衔接后面的建造者模式)为抽象类,可以理解为店长为做奶茶了制作了一个“食谱”(里面包含制作需要的原料及方法)以及店长规定仓库里原料的存放位置,后厨打开门根据原料的存放位置取原料,其余事情店长不需要做。
public abstract class MilkTeaBuilder {
public String name;
public Milk milk;
public Tea tea;
public Factory cloneFactory;
public abstract void buildMilk();
public abstract void buildTea();
public abstract void create();
/**
* 打开仓库的门,按照工厂的序号取原料
*/
public Factory openDoor(int factorId) {
FactoryCache.loadCache();
if(factorId==1) {
cloneFactory=(Factory) FactoryCache.getFactory("1");
}
else {
cloneFactory=(Factory) FactoryCache.getFactory("2");
}
return cloneFactory;
}
}
3、建造者模式
(7)在没有用适配器模式之前需要用到加工奶类和加工茶类两个机器。MilkMachine相当于Adaptee即原有的旧机器(衔接适配器模式)。
public class MilkMachine {
public static void makingMilk(Milk milk) {
String makeString=milk.getMilk();
System.out.println(makeString);
}
}
public class TeaMachine {
public static void makingTea(Tea tea) {
String makeString=tea.getTea();
System.out.println(makeString);
}
}
(8)由后厨们(具体建造者ConcreteBuilder)按照建造者Builder的“食谱”去仓库取原料再用机器制作具体的奶茶。
public class GreenMilkConBuilder extends MilkTeaBuilder{
@Override
public void buildMilk() {
openDoor(1);
milk=cloneFactory.CreateMilk();
System.out.println("Factory: " + cloneFactory);
}
@Override
public void buildTea() {
openDoor(1);
tea=cloneFactory.CreateTea();
System.out.println("Factory: " + cloneFactory);
}
@Override
public void create() {
System.out.println("正在准备牛奶绿茶中......");
MilkMachine.makingMilk(milk);
TeaMachine.makingTea(tea);
}
}
public class GreenYogurtConBuilder extends MilkTeaBuilder{
@Override
public void buildMilk() {
openDoor(2);
milk=cloneFactory.CreateMilk();
System.out.println("Factory: " + cloneFactory);
}
@Override
openDoor(1);
tea=cloneFactory.CreateTea();
System.out.println("Factory: " + cloneFactory);
}
@Override
public void create() {
System.out.println("正在开始准备酸奶绿茶中......");
MilkMachine.makingMilk(milk);
TeaMachine.makingTea(tea);
}
}
public class RedMilkConBuilder extends MilkTeaBuilder{
@Override
public void buildMilk() {
openDoor(1);
milk=cloneFactory.CreateMilk();
System.out.println("Factory: " + cloneFactory);
}
@Override
public void buildTea() {
openDoor(2);
tea=cloneFactory.CreateTea();
System.out.println("Factory: " + cloneFactory);
}
@Override
public void create() {
System.out.println("正在准备牛奶红茶中......");
MilkMachine.makingMilk(milk);
TeaMachine.makingTea(tea);
}
}
public class RedYogurtConBuilder extends MilkTeaBuilder{
@Override
public void buildMilk() {
openDoor(2);
milk=cloneFactory.CreateMilk();
System.out.println("Factory: " + cloneFactory);
}
@Override
public void buildTea() {
openDoor(2);
tea=cloneFactory.CreateTea();
}
@Override
public void create() {
System.out.println("正在开始准备酸奶红茶中......");
MilkMachine.makingMilk(milk);
TeaMachine.makingTea(tea);
}
}
4、适配器模式
(9)由于用两个机器制造奶茶太繁琐,但是又不能在现有的机器里同时混合两种原料制作,所以老板打算更新设备,买了一个新升级加工牛奶的机器(可以同时加工茶类)newMachineTarget(接口)。
MilkMachine相当于Adaptee即原有的旧机器。
public interface newMachineTarget {
public void newmaking(Milk milk,Tea tea);
}
(10)新机器的实体Adapter有以前旧机器MilkMachine的功能,还添加了TeaMachine的功能。
public class Adapter extends MilkMachine implements newMachineTarget {
public void newmaking(Milk milk,Tea tea) {
makingMilk(milk);
//新加的烤茶功能
String makeString=tea.getTea();
System.out.println(makeString);
}
}
(11)继续建造者模式后厨们(具体建造者ConcreteBuilder)使用新机器制作奶茶,将上述第(9)改成此步骤,修改 create()方法:
将
MilkMachine.makingMilk(milk);
TeaMachine.makingTea(tea);
改成
newMachineTarget machine=new Adapter();
machine.newmaking(milk,tea);//用新机器加工
其余GreenYogurtConBuilder、RedMilkConBuilder、RedYogurtConBuilder改法相同,如下
public class GreenMilkConBuilder extends MilkTeaBuilder{
@Override
public void buildMilk() {
openDoor(1);
milk=cloneFactory.CreateMilk();
System.out.println("Factory: " + cloneFactory);
}
@Override
public void buildTea() {
openDoor(1);
tea=cloneFactory.CreateTea();
System.out.println("Factory: " + cloneFactory);
}
@Override
public void create() {
System.out.println("正在准备牛奶绿茶中......");
newMachineTarget machine=new Adapter();
machine.newmaking(milk,tea);//用新机器加工
}
}
(12)奶茶一切准备就绪,可以开店了。店里有服务员(指挥者类Director)一方面它隔离了客户与生产过程,即客户只看到菜单只能选择商品不能看到生产过程;另一方面它负责控制产品的生成过程。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象,简单来说服务员Director和店长Builder说顾客Client要红茶,然后店长Builder安排具体后厨ConcreteBuilder生产相应产品。
public class MilkTeashop {
public void menu() {
System.out.println("************MENU************");
System.out.println("1.RedMilk 2.GreenMilk");
System.out.println("3.RedYogurt 4.GreenYogurt");
System.out.println("*************END*************");
}
public void making(MilkTeaBuilder milkTea) {
milkTea.buildMilk();
milkTea.buildTea();
milkTea.create();
}
public MilkTeaBuilder selectMilkTea() {
MilkTeaBuilder milkTea=null;
Scanner s =new Scanner(System.in);
System.out.print("请选择你的饮料");
int num=s.nextInt();
switch (num) {
case 1:
milkTea=new RedMilkConBuilder();
break;
case 2:
milkTea=new GreenMilkConBuilder();
break;
case 3:
milkTea=new RedYogurtConBuilder();
break;
case 4:
milkTea=new GreenYogurtConBuilder();
break;
default:
System.out.println("输入错误!");
break;
}
making(milkTea);
return milkTea;
}
}
(13)测试奶茶店的运行情况
public class DrinkClient {
public static void main(String[] args) {
MilkTeashop coco = new MilkTeashop();
coco.menu();
coco.selectMilkTea();
}
}