设计模式-建造者模式

Posted shoulinniao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-建造者模式相关的知识,希望对你有一定的参考价值。

一、建造者模式概念

建造者模式是最复杂的创建型模式,它将客户端与包含多个组成部分的复杂对象的创建分离,客户端无需知道复杂对象的内部组成部分与装配模式,只需要知道建造者的类型即可。

建造者模式关注 该复杂对象 是如何一步步创建而成的。


 

二、建造者模式的角色

  1. 产品类:被构建的复杂对象,有好多属性作为组成部件,具体建造者创建该产品的内部组成,表示并定义它的装配过程。
  2. 抽象建造者:创建一个产品对象 供子类设值(装配),一般有两类方法,一类是buildPartX(),子类实现对产品属性的设值,一类是getResult(),用于返回复杂对象。
  3. 具体建造者:实现抽象建造者中的方法,其中各个buildPartX()实现后 即确定了复杂产品的各属性值。也可以提供一个方法返回创建好的复杂产品对象。
  4. 指挥者:又称导演类,负责安排复杂对象的建造次序,指挥者和抽象建造者关联,在construct()建造方法中调用建造者对象的装配方法,完成复杂产品的建造。

理解:每一个具体建造者类相当于一个具体产品,通过设值装配复杂对象。指挥者里创建抽象建造者对象,当作具体建造者对象使用(设值),然后返回。 建造者里创建产品对象,设值后返回。

 


 

三、举例

KFC如何创建套餐:套餐是一个复杂对象,包含主食(如汉堡、鸡肉卷)和饮料(如果汁、可乐)等组成部分,不同套餐有不同的组成部分,然后KFC服务员根据客户需求一步一步装配套餐,构造出一份完整的套餐,返回给客户。套餐A=汉堡+可乐。套餐B=鸡肉卷+果汁。

产品类:Meal

技术图片
package build;

public class Meal {//产品类,套餐类
    private String food;
    private String drink;
    public String getFood() {
        return food;
    }
    public void setFood(String food) {
        this.food = food;
    }
    public String getDrink() {
        return drink;
    }
    public void setDrink(String drink) {
        this.drink = drink;
    }
}
Meal

抽象建造者MealBuilder 和 具体建造者MealBuilderA、MealBuilderB

技术图片
package build;

public abstract class MealBuilder {//抽象套餐,建造者类
    protected Meal meal=new Meal();//这个类对象主要是给子类设值的
    public abstract void buildFood();
    public abstract void buildDrink();
    public Meal getMeal() {
        return meal;
    }
}

class MealBuilderA extends MealBuilder{//套餐A 具体建造者
    public void buildFood() {
        meal.setFood("汉堡");
    }
    public void buildDrink() {
        meal.setDrink("可乐");
    }
}

class MealBuilderB extends MealBuilder{//套餐B 具体建造者
    public void buildFood() {
        meal.setFood("鸡肉卷");
    }
    public void buildDrink() {
        meal.setDrink("果汁");
    }
}
MealBuilder

指挥者:KFCWaiter

技术图片
package build;

public class KFCWaiter {//指挥者类
    private MealBuilder mb;
    public void setMealBuilder(MealBuilder mb) {
        this.mb=mb;
    }
    public Meal construct() {
        mb.buildFood();
        mb.buildDrink();
        return mb.getMeal();
    }
}
KFCWaiter

模拟DAO:XMLUtil.java和config.xml

技术图片
package build;

import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
import java.net.URL;

public class XMLUtil {
    
    public static Object getBean() {
        try {
            //创建DOM文档对象
            DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();//文档制造者工厂创建了一个 文档制造者工厂对象
            DocumentBuilder builder=dFactory.newDocumentBuilder();//文档制造者类 通过 文档制造者工厂 创造一个 文档制造者对象
            Document doc;//文档制造者 创建 文档
            doc=builder.parse(new File("src/build/config.xml"));//解析xml文件
            
            //获取包含类名的文本节点
            NodeList nl=doc.getElementsByTagName("className");//文本节点列表里有很多被className标签夹着的内容
            Node classNode=nl.item(0).getFirstChild();
            //item(0)表示引用列表里第一个节点,这里只有一个。getFirstChild表示获取该节点的第一个孩子。
            String cName=classNode.getNodeValue();

            //通过类名生成实例对象并返回
            Class c=Class.forName(cName);
            Object obj=c.newInstance();
            return obj;
        }catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
XMLUtil
技术图片
<?xml version="1.0"?>
<config>
    <className>build.MealBuilderA</className>
</config>
config.xml

客户端:Client

技术图片
package build;

public class Client {
    public static void main(String[] args) {
        //动态确定套餐种类
        MealBuilder mb=(MealBuilder)XMLUtil.getBean();
        
        //服务员是指挥者
        KFCWaiter waiter=new KFCWaiter();
        
        //服务员准备套餐,这个套餐mb是从XML文件里搞来的一个具体建造者类
        waiter.setMealBuilder(mb);
        
        //客户获得套餐
        Meal meal=waiter.construct();

        System.out.println("套餐组成:");
        System.out.println(meal.getFood());
        System.out.println(meal.getDrink());
    }

}
Client

 


 

四、课后习题

某游戏软件中任务角色包括多种类型,不同类型的任务角色,其性别、脸型、服装、发型等外部特性有所差异,使用建造者模式创建任务角色对象,要求绘制类图并编程实现。

妲己:女,锥子脸,咖啡女仆,短发
甄姬:女,瓜子脸,花好人间,斜刘海
宫本:男,菱形脸,鬼剑武藏,冲天辫

产品类

技术图片
package homework;

public class Role {//产品类 角色Role
    private String name;
    private String sex;
    private String face;
    private String clothes;
    private String hair;
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getFace() {
        return face;
    }
    public void setFace(String face) {
        this.face = face;
    }
    public String getClothes() {
        return clothes;
    }
    public void setClothes(String clothes) {
        this.clothes = clothes;
    }
    public String getHair() {
        return hair;
    }
    public void setHair(String hair) {
        this.hair = hair;
    }

}
Role

抽象建造者和具体建造者类

技术图片
package homework;

public abstract class Rolebuilder {//建造者  角色建造者

    protected Role role=new Role(); 
    public abstract void build();
    public Role getRole() {
        return role;
    }
}

class Daji extends Rolebuilder{//具体建造者  妲己:女,锥子脸,咖啡女仆,短发
    public void build() {
        role.setName("妲己");
        role.setSex("女");
        role.setFace("锥子脸");
        role.setClothes("咖啡女仆");
        role.setHair("短发");
    }
}


class Zhenji extends Rolebuilder{//具体建造者  甄姬:女,瓜子脸,花好人间,斜刘海
    public void build() {
        role.setName("甄姬");
        role.setSex("女");
        role.setFace("瓜子脸");
        role.setClothes("花好人间");
        role.setHair("斜刘海");
    }
}

class Gongben extends Rolebuilder{//具体建造者  宫本:男,菱形脸,鬼剑武藏,冲天辫
    public void build() {
        role.setName("宫本武藏");
        role.setSex("男");
        role.setFace("菱形脸");
        role.setClothes("鬼剑武藏");
        role.setHair("冲天辫");
    }
}
Rolebuilder

指挥者

技术图片
package homework;

public class Player {//指挥者  玩家
    private Rolebuilder rb;
    public void setRolebuilder(Rolebuilder rb) {
        this.rb=rb;
    }
    
    public Role construct() {
        rb.build();
        return rb.getRole();
    }
}
Player

模拟DAO

技术图片
package homework;

import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
import java.net.URL;

public class XMLUtil {
    
    public static Object getBean() {
        try {
            //创建DOM文档对象
            DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();//文档制造者工厂创建了一个 文档制造者工厂对象
            DocumentBuilder builder=dFactory.newDocumentBuilder();//文档制造者类 通过 文档制造者工厂 创造一个 文档制造者对象
            Document doc;//文档制造者 创建 文档
            doc=builder.parse(new File("src/homework/config.xml"));//解析xml文件
            
            //获取包含类名的文本节点
            NodeList nl=doc.getElementsByTagName("className");//文本节点列表里有很多被className标签夹着的内容
            Node classNode=nl.item(0).getFirstChild();
            //item(0)表示引用列表里第一个节点,这里只有一个。getFirstChild表示获取该节点的第一个孩子。
            String cName=classNode.getNodeValue();

            //通过类名生成实例对象并返回
            Class c=Class.forName(cName);
            Object obj=c.newInstance();
            return obj;
        }catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
XMLUtil
技术图片
<?xml version="1.0"?>
<config>
    <className>homework.Zhenji</className>
</config>
config.xml

客户端

技术图片
package homework;

public class Client {
    public static void main(String[] args) {
        //从XML文档里知道要做成哪个具体建造者,通过指挥者对象设值、建造、后返回
        Rolebuilder rb=(Rolebuilder)XMLUtil.getBean();
        Player player=new Player();
        player.setRolebuilder(rb);
        Role role=player.construct();
        System.out.println("姓名:"+role.getName());
        System.out.println("性别:"+role.getSex());
        System.out.println("脸型:"+role.getFace());
        System.out.println("服饰:"+role.getClothes());
        System.out.println("发行:"+role.getHair());
    }
}
Client

 

以上是关于设计模式-建造者模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之建造者模式

建造者模式(Builder)

设计模式 创建者模式 -- 建造者模式

设计模式从青铜到王者第八篇:创建型模式之建造者模式(BuilderPattern)

Java设计模式-建造者模式

设计模式:学习笔记——建造者模式