设计模式之抽象工厂、建造者模式结合

一、抽象工厂

1.概述

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。可以理解成是多个工厂方法的组合。

2.解决问题

在工厂方法模式中,具体创建者每次使用都只能创建一个同类型的对象,假如现在需要的是多个不同类型的对象,工厂方法就满足不了需求了。这时我们可以把多个工厂方法组合到一个类,这就是抽象工厂模式,它就是专门用来创建多个产品,也可以说是创建产品家族的。

3.类图

设计模式之抽象工厂、建造者模式结合_第1张图片

4.成员角色

Creator抽象工厂:定义了一系列的产品生产行为,客户端直接引用,由未实现的工厂方法组成,子类必须实现其工厂方法创建产品家族。

ConcreteCreator具体工厂:实现抽象工厂接口,负责实现工厂方法,一个具体工厂可以创建一组产品。

Product抽象产品:产品族的父类,由此可以衍生很多子产品。

ProductA1/A2/B1/B2具体产品:实现了相应的产品接口,衍生自抽象产品,由工厂方法直接创建。

首先搞清楚产品等级和产品族的概念,比如:手机有小米手机、华为手机,它们都是手机,这些具体的手机和抽象手机就构成了一个产品等级结构。同样的,路由器有小米路由器,华为路由器,这些具体的路由器和抽象路由器就构成了另外一个产品等级结构,实质上产品等级结构即产品的继承结构。小米手机位于手机产品等级结构中,小米路由器位于路由器的产品等级结构中,而小米手机和小米路由器都是小米公司生产的,就构成了一个产品族,同理,华为手机和华为路由器也构成了一个产品族 。划重点就是产品族中的产品都是由同一个工厂生产的,位于不同的产品等级结构
设计模式之抽象工厂、建造者模式结合_第2张图片
抽象工厂模式的两种情况:①符合开闭原则;②不符合开闭原则(又称抽象工厂模式“开闭原则”的倾斜性)

  • ①符合开闭原则情况
    增加产品族对于增加新的产品族抽象工厂模式很好地支持开闭原则,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。
  • ②不符合开闭原则情况
    增加新的产品等级结构对于增加新的产品等级结构 ,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了开闭原则。

5.优缺点

优点
​ 具体产品隔离,无需关系创建细节。
​ 将一个系列的产品统一到一起创建。
​ 增加新的产品族很方便,无须修改已有系统,符合开闭原则。

缺点
增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了开闭原则
​ 增加了系统的抽象性和理解难度。

6.使用场景

​ 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节。
​ 系统中有多于一个的产品族,但每次只使用其中某一产品族。
属于同一个产品族的产品将在一起使用, 这一约束必须在系统的设计中体现出来。
产品等级结构稳定, 设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。

7.简单工厂模式、工厂方法模式、抽象工厂的区别

(1)简单工厂模式:定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。不符合开闭原则,中心是一个实体工厂类,工厂负责创建的对象比较少,客户端只知道传入工厂的参数,不需要关注对象创建的细节。简单来说:只有一个实体工厂类;一个实体工厂类生产所有的产品类,工厂根据传入的参数判断具体生产哪个产品给客户。

(2)工厂方法模式:定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。只有一个抽象产品类;一个实体工厂类生产一种产品类,客户需要知道生产该产品的工厂类名称。

(3)抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。有多个抽象产品类;一个实体工厂类可以生产多种产品类,客户可以从一个工厂获得所有想要的产品。

二、建造者模式

1.概述

将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。

2.解决问题

建造者模式主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

3.类图

设计模式之抽象工厂、建造者模式结合_第3张图片

4.成员角色

建造者(Builder):为创建一个产品对象的各个部件指定抽象接口。

具体建造者(ConcreteBuilder):实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并 提供一个检索产品的接口。

指挥者(Director):指挥并构造一个使用Builder接口的对象,负责和客户(Client)对话。

产品(Product):表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

5.优缺点

优点
用户只需要指定要建造的类型就可以得到它们,而具体的建造过程和细节不需要知道。

​ 建造代码与表示相分离,如果要改变一个产品的内部表示,只要再定义一个新的具体的建造者就可以了。

​ 建造过程由指挥者来控制,建造细节由一个抽象类来控制,对于实现建造细节的具体类来说,不会遗漏某一个步骤。

缺点

​ 产品必须有共同点,范围有限制。

​ 如内部变化复杂,会有很多的建造类。

6.使用场景

建造者模式适用于所创建的产品具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,如做奶茶和做烧饼。

三、抽象工厂模式和建造者模式结合实例

1.背景

​ 以开奶茶店为例,奶茶的原料可以由多个厂提供,使用抽象工厂来统一供应原料。假如配制奶茶只需要奶类和茶类,这些配件是稳定的,配制过程也是稳定的,但是搭配方式是多样的,比如牛奶红茶,牛奶绿茶等。

2.类图

设计模式之抽象工厂、建造者模式结合_第4张图片

3.代码步骤

(1)首先创建工厂,也就是原材料总工厂,相当于一个大型市场,所有的实体工厂都开在这里。

public interface Factory {

    public Milk CreateMilk();

    public Tea CreateTea();

}

(2)原材料工厂中涉及很多原材料产品种类,现在创建这些产品种类,即创建抽象产品。

public interface Milk {

}

public interface Tea {

}

(3)接着创建所需的具体产品。

public class PureMilk implements Milk {
	PureMilk(){
		System.out.print("加纯牛奶");
	}
}

public class Yogurt implements Milk {
	public Yogurt(){
		System.out.print("加酸奶");
	}
}

public class GreenTea implements Tea {
	public GreenTea(){
    	System.out.print("加绿茶");
	}
}

public class RedTea implements Tea {
	public RedTea()	{
		System.out.print("加红茶");
	}
}

(4)具体原材料准备好了,则分到具体的工厂制作。

public class AFactory implements 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 implements 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;
    }
}

以上为抽象工厂模式的步骤。

下面开始建造者模式。

(5)有了原材料工厂,可以着手制作奶茶了。店长(奶茶建造者Builder)为抽象类,可以理解为店长为做奶茶了制作了一个“食谱”(里面包含制作需要的原料及方法)其余事情店长不需要做。

public abstract class MilkTeaBuilder {
	
	public String name;
	
	public Milk milk;
	
	public Tea tea;
	
	public abstract void buildMilk();
	
	public abstract void buildTea();
	
	public abstract void create();
	
}

(6)由后厨们(具体建造者ConcreteBuilder)按照建造者Builder的“食谱”制作具体的奶茶,原料由市场里的工厂提供。

public class GreenMilkConBuilder extends MilkTeaBuilder{
	@Override
	public void buildMilk() {
		Factory factory;		
		factory=new AFactory();
		milk=factory.CreateMilk();
	}
	@Override
	public void buildTea() {
		Factory factory;		
		factory=new AFactory();
		tea=factory.CreateTea();
	}
	@Override
	public void create() {
		System.out.print("正在准备牛奶绿茶中......");		
	}
}

public class GreenYogurtConBuilder extends MilkTeaBuilder{
	@Override
	public void buildMilk() {
		Factory factoryB;
		factoryB=new BFactory();
		milk=factoryB.CreateMilk();
	}
	@Override
	public void buildTea() {
		Factory factoryA;
		factoryA=new AFactory();
		tea=factoryA.CreateTea();
	}
	@Override
	public void create() {
		System.out.print("正在开始准备酸奶绿茶中......");	
	}
}

public class RedMilkConBuilder extends MilkTeaBuilder{
	Factory factoryA;
	Factory factoryB;
	public RedMilkConBuilder() {
		factoryA=new AFactory();	
		factoryB=new BFactory();	
	}
	@Override
	public void buildMilk() {
		milk=factoryA.CreateMilk();
	}
	@Override
	public void buildTea() {
		tea=factoryB.CreateTea();
	}
	@Override
	public void create() {	
		System.out.println("正在准备牛奶红茶中......");
	}
}

public class RedYogurtConBuilder extends MilkTeaBuilder{
	@Override
	public void buildMilk() {
		Factory factoryB;
		factoryB=new BFactory();
		milk=factoryB.CreateMilk();
	}
	@Override
	public void buildTea() {
		Factory factoryB;
		factoryB=new AFactory();
		tea=factoryB.CreateTea();
	}
	@Override
	public void create() {
		System.out.print("正在开始准备酸奶红茶中......");	
	}
}

(7)奶茶一切准备就绪,可以开店了。店里有服务员(指挥者类Director)一方面它隔离了客户与生产过程,即客户只看到菜单只能选择商品不能看到生产过程;另一方面它负责控制产品的生成过程。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象,简单来说服务员Director和店长Builder说顾客Client要红茶,然后店长Builder安排具体后厨ConcreteBuilder生产相应产品。

import java.util.Scanner;

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.create();
		milkTea.buildMilk();
		milkTea.buildTea();
	}
	
	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;
	}
}

(8)测试一下奶茶店的运行情况

public class DrinkClient {

	public static void main(String[] args) {
		MilkTeashop coco = new MilkTeashop();
		coco.menu();
		coco.selectMilkTea();
	}
}

结果

设计模式之抽象工厂、建造者模式结合_第5张图片

由于水平有限,文章中难免有错误的地方,欢迎指出错误或不足之处,共同进步 Thanks♪(・ω・)ノ

你可能感兴趣的:(设计模式,java,设计模式,程序人生,经验分享)