文档章节

浅谈设计模式之建造者模式

佛系程序猿灬
 佛系程序猿灬
发布于 07/03 20:10
字数 1460
阅读 2759
收藏 37

介绍

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

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

何时使用:一些基本部件不会变,而其组合经常变化的时候。

如何解决:将变与不变分离开。

关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。3、SQL中的PreparedStatement

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

实现

我们假设一个快餐店的商业案例,去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。其中,一个典型的套餐可以是一个汉堡(Burger)和一杯冷饮(Cold drink)。汉堡(Burger)可以是素食汉堡(Veg Burger)或鸡肉汉堡(Chicken Burger),它们是包在纸盒中。冷饮(Cold drink)可以是可口可乐(coke)或百事可乐(pepsi),它们是装在瓶子中。

我们将创建一个表示食物条目(比如汉堡和冷饮)的 Item 接口和实现 Item 接口的实体类,以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类,汉堡是包在纸盒中,冷饮是装在瓶子中。

然后我们创建一个 Meal 类,带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilderBuilderPatternDemo,我们的演示类使用 MealBuilder 来创建一个 Meal

代码示例:

1、创建一个表示食物条目和食物包装的接口 ItemPacking

package builder.item.service;

import builder.pack.service.Packing;

/**
 * 食物条目接口
 * @author lihaoshan
 * @date 2018-06-27
 * */
public interface Item {

    /**名字*/
    public String name();

    /**价格*/
    public Double price();


    public Packing packing();
}
package builder.pack.service;

/**
 * 包装接口
 * @author lihaoshan
 * @date 2018-06-27
 * */
public interface Packing {

    /**包装*/
    public String pack();
}

2、创建 Packing 接口的实现类

package builder.pack.impl;

import builder.pack.service.Packing;

/**
 * 包装接口实现类【瓶装】
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class Bottle implements Packing{

    @Override
    public String pack(){
        return "瓶装";
    }
}
package builder.pack.impl;

import builder.pack.service.Packing;

/**
 * 包装接口实现类【纸盒包装】
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class Wrapper implements Packing {

    @Override
    public String pack(){
        return "纸盒包装";
    }
}

3、创建实现 Item 接口的抽象类

package builder.item.impl;

import builder.pack.impl.Wrapper;
import builder.item.service.Item;
import builder.pack.service.Packing;

/**
 * 食物条目实现抽象类【汉堡】
 * @author lihaoshan
 * @date 2018-06-28
 * */
public abstract class Burger implements Item{

    @Override
    public Packing packing(){
        return new Wrapper();
    }

    @Override
    public abstract Double price();

}
package builder.item.impl;

import builder.pack.impl.Bottle;
import builder.item.service.Item;
import builder.pack.service.Packing;

/**
 * 食物条目实现抽象类【可乐】
 * @author lihaoshan
 * @date 2018-06-28
 * */
public abstract class ColdDrink implements Item{

    @Override
    public Packing packing(){
        return new Bottle();
    }

    @Override
    public abstract Double price();
}

4、创建扩展了 BurgerColdDrink 的实体类

package builder.po;

import builder.item.impl.Burger;

/**
 * 扩展Burger的实体类【鸡肉汉堡】
 *
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class ChickenBurger extends Burger{

    @Override
    public Double price(){
        return 30.0;
    }

    @Override
    public String name(){
        return "鸡肉汉堡";
    }
}
package builder.po;

import builder.item.impl.ColdDrink;

/**
 * 扩展ColdDrink的实体类【可口可乐】
 *
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class Coke extends ColdDrink{

    @Override
    public Double price(){
        return 10.0;
    }

    @Override
    public String name(){
        return "可口可乐";
    }
}
package builder.po;

import builder.item.impl.ColdDrink;

/**
 * 扩展ColdDrink的实体类【百事可乐】
 *
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class Pepsi extends ColdDrink{

    @Override
    public Double price(){
        return 12.0;
    }

    @Override
    public String name(){
        return "百事可乐";
    }
}
package builder.po;

import builder.item.impl.Burger;

/**
 * 扩展Burger的实体类【素食汉堡】
 *
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class VegBurger extends Burger {

    @Override
    public Double price() {
        return 25.0;
    }

    @Override
    public String name() {
        return "素食汉堡";
    }
}

5、创建点餐类 Meal,带有食物条目对象 

package builder;

import builder.item.service.Item;

import java.util.ArrayList;
import java.util.List;

/**
 * 点餐类,带有食物条目对象
 *
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class Meal {

    /**食物条目对象*/
    private List<Item> items = new ArrayList<Item>();

    /**
     * 点餐方法
     *
     * @param item
     * */
    public void addItem(Item item){
        items.add(item);
    }

    /**
     * 点餐费用
     *
     * */
    public Double getCost(){

        Double cost = 0.0;
        for (Item item : items) {
            cost +=item.price();
        }
        return cost;
    }

    /**
     * 展示食物条目
     *
     * */
    public void showItems(){
        System.out.println("菜单\t\t\t\t包装\t\t\t\t费用\n");
        for (Item item : items) {
            System.out.print(item.name()+"\t\t\t"+item.packing().pack()+"\t\t\t"+item.price()+"\n");
        }
    }
}

6、创建一个点餐服务类 MealBuilder 

package builder;

import builder.po.ChickenBurger;
import builder.po.Coke;
import builder.po.Pepsi;
import builder.po.VegBurger;

/**
 * 点餐服务类
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class MealBuilder {

    /**
     * 素食套餐
     * */
    public Meal prepareVegMeal(){
        Meal meal = new Meal();
        meal.addItem(new VegBurger());
        meal.addItem(new Coke());
        return meal;
    }

    /**
     * 非素食套餐
     * */
    public Meal prepareNonVegMeal(){
        Meal meal = new Meal();
        meal.addItem(new ChickenBurger());
        meal.addItem(new Pepsi());
        return meal;
    }

}

7、创建一个测试类 BuiderPatternDemo

package builder;

import org.junit.Test;

/**
 * 建造者模式 测试类
 * @author lihaoshan
 * @date 2018-06-28
 * */
public class BuilderPatternDemo {

    @Test
    public void test(){
        MealBuilder mealBuilder = new MealBuilder();

        Meal vegMeal = mealBuilder.prepareVegMeal();
        System.out.println("***************素食餐***************");
        vegMeal.showItems();
        System.out.println("总合计: " +vegMeal.getCost());

        Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
        System.out.println("\n\n***************非素食餐***************");
        nonVegMeal.showItems();
        System.out.println("总合计: " +nonVegMeal.getCost());
    }
}

8、运行结果如下:

源码地址

码云:https://gitee.com/haoshan/design_pattern

 

欢迎各位大佬关注我的个人微信订阅号:

© 著作权归作者所有

共有 人打赏支持
佛系程序猿灬
粉丝 10
博文 7
码字总数 10852
作品 0
南京
程序员
加载中

评论(5)

句龙胤
句龙胤
在动态语言中,不需要这些类。最好的方法是数据驱动,只需要要几个函数解析数据表,简单的结构和代码就能完成极为复杂的组合效果。一个例子是魔兽世界的技能,纯数据驱动。
A
AntennaBaby

引用来自“jiabei”的评论

为什么百事可乐比可口可乐贵两块钱
666老哥真的严格.
♂茶舞
♂茶舞
这与组合模式有什么区别?
佛系程序猿灬
佛系程序猿灬

引用来自“jiabei”的评论

为什么百事可乐比可口可乐贵两块钱
看来大佬是用心了,看问题很是犀利啊
jiabei
jiabei
为什么百事可乐比可口可乐贵两块钱
JavaScript设计模式系列二之建造者模式(附案例源码)

文章初衷 设计模式其实旨在解决语言本身存在的缺陷, 目前javaScript一些新的语法特性已经集成了一些设计模式的实现, 大家在写代码的时候,没必要为了用设计模式而去用设计模式, 那么我这边为什...

小钱钱阿圣
2017/09/11
0
0
设计模式(Swift) - 3.观察者模式、建造者模式

上一篇 设计模式(Swift) - 2.单例模式、备忘录模式和策略模式中讲了三种常见的设计模式. 单例模式: 限制了类的实例化,一个类只能实例化一个对象,所有对单例对象的引用都是指向了同一个对象....

Dariel
07/01
0
0
设计模式快速学习(四)建造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。将一个复杂的构建与其表示相分离,使...

微笑面对Life
08/15
0
0
设计模式8——Builder设计模式

Builder建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。Builder模式是一步一步创建一个复杂的对象,它允许用户可以只通过指定复杂对象的类型和内容就...

小米米儿小
2013/12/11
0
0
java设计模式-- 单例模式

在很久之前,也就是在大二暑假的时候,那时候看马士兵的视频教程中有提到很多的设计模式。 java的设计模式大致可以分为3大类,23种设计模式。 其中,创建型模式有5种:单例模式、建造者模式、...

爱学习的逃课君
2014/11/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

win10下端口被占用解决办法

win10下端口被占用解决办法 昨天还好好的tomcat,今天启动时候发现tomcat无法启动,看报错信息显示8080端口被占用。 解决办法如下:按win+R输入cmd打开控制台,输入 netstat -ano|findstr 8...

DemonsI
22分钟前
1
0
yum apt chrome 常用软件的SOCKS 代理设置

yum 设置: 在/etc/yum.conf 增加一行,内容为: 在apt-get (apt) 上使用socks代理 chrome socks代理:

idoz
23分钟前
0
0
因 php 默认的 url encode 编码标准引发的一个问题

先看常用的校验请求合法性的一个方式 function createToken($params) { $secretKey = 'secretKey'; ksort($params); $query = http_build_query($params); $token = md5......

anoty
26分钟前
8
0
微信小程序页面栈管理

页面路由 在小程序中所有页面的路由全部由框架进行管理。 页面栈 框架以栈的形式维护了当前的所有页面。当发生路由切换的时候,页面栈的表现如下: 路由方式 页面栈表现 初始化 新页面入栈 ...

昙花一现
今天
2
0
es6 let使用总结

中午偷个闲做个es6let的使用总结 作用域块 在作用域块中声明的变量不受外部的影响,见例子 {let a= 10;{let a= 20;console.log('子作用域', a);// 20}console.log('父作用域', a);// 10...

莫西摩西
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部