zoukankan      html  css  js  c++  java
  • 设计模式:建造者模式及在jdk中的体现,建造者模式和工厂模式区别


    0、背景


    建造模式(Builder模式)

    假如有一个需求:盖房子,盖房子过程是一致的:打桩、砌墙、封顶。但是房子是各式各样的,最后盖出来的房子可能是高楼或别墅。

    根据直接的思路,不用设计模式思想,我们也许会:

    1. 写一个 CommonHouse 抽象类,然后里面规定了打桩、砌墙、封顶三个方法;
    2. 让不同房子继承这个类;
    3. 最后调用的时候调用分别的方法即可。

    在继承抽象类、子类区分这一块,思想没有问题,问题出现这些类本身。

    缺点:

    过于简单,将产品(房子)和创建产品(房子建造流程)封装在了一起,耦合性增强了。(可以理解为,面向对象的思想里,房子虽然是一个类,拥有自己的方法,但是房子不应该拥有建造自己的方法)

    解决方法:

    解耦 - > 建造者模式。


    一、建造者模式


    建造者模式(Builder Pattern)又叫生成器模式,是一种对象构建模式(创建型),可以将复杂对象的建造过程抽象出来(抽象类),使这个抽象过程的不同实现方法能构造出不同表现(属性)的对象。

    建造模式允许用户只通过指定复杂对象的类型和内容就可以构建他们,用户不需要知道内部的具体构建细节。

    建造者模式的四个角色:

    1. Product产品:一个具体产品对象;
    2. Builder(抽象建造者):创建Product对象指定的 接口或者抽象类;
    3. ConcreteBuilder具体建造者:实现接口,构建和装配各个部件;
    4. Director指挥者:构建一个使用Builder接口的对象,主要用于创建一个复杂度对象,有两个作用:一是隔离客户与对象的生产过程,二是负责控制产品对象的生产过程。

    他们之间的关系,我们用类图来解释:

    • Directer里面聚合一个Builder实际上使用的是他的实现类ConcreteBuilder;
    • ConcreteBuilder可以有很多,就是所谓的不同的房子的建造者。

    因为getRusult是一样的,所以暂时不用接口,用抽象类实现Builder,代码如下:

    /*
        产品,对应product
    */
    public class House {
        private String base;
        private String wall;
        private String roof;
        //对应getset方法
    }
    
    /*
        抽象的建造者,对应Builder
    */
    public abstract class HouseBuilder {
        protected House house = new House();
        //写好流程的各个方法,但不约束具体执行
        public abstract void buildBasic();
        public abstract void buildWalls();
        public abstract void buildRoof();
        //建造方法,返回建造结果
        public House buildHouse(){
            return house;
        }
    }
    
    /*
        普通房子制造流程,继承抽象类
        可以看到,制造流程在这里,而House类拥有房子的属性,他们是分开的
        应是对House的操作,这里省略
    */
    public class CommonHouse extends HouseBuilder{
        @Override
        public void buildBasic() {
            System.out.println("普通房子:建造地基。。。");
        }
        @Override
        public void buildWalls() {
            System.out.println("普通房子:砌墙。。。");
        }
        @Override
        public void buildRoof() {
            System.out.println("普通房子:盖屋顶。。。");
        }
    }
    
    /*
        另一个实现类,本来应是对House的操作,这里省略
    */
    public class HighHouse extends HouseBuilder {
        @Override
        public void buildBasic() {
            System.out.println("高楼:建造地基。。。");
        }
        @Override
        public void buildWalls() {
            System.out.println("高楼:砌墙。。。");
        }
        @Override
        public void buildRoof() {
            System.out.println("高楼:盖屋顶。。。");
        }
    }
    
    /*
        Director,聚合建造者HouseBuilder
        同时决定制作流程,最后调用建造者的buildHouse方法返回
    */
    public class Director {
        HouseBuilder houseBuilder = null;
        //通过构造器聚合
        public Director(HouseBuilder houseBuilder) {
            this.houseBuilder = houseBuilder;
        }
        //通过setter方法聚合
        public void setHouseBuilder(HouseBuilder houseBuilder) {
            this.houseBuilder = houseBuilder;
        }
        //指挥具体建造流程,先后顺序不由Builder决定
        public House constructHouse(){
            houseBuilder.buildBasic();
            houseBuilder.buildWalls();
            houseBuilder.buildRoof();
            return houseBuilder.buildHouse();
        }
    }
    
    /*
        客户端
    */
    public class Client {
        public static void main(String[] args) {
            //new房子
            CommonHouse commonHouse = new CommonHouse();
            //new指挥者
            Director director = new Director(commonHouse);
            //完成盖房
            House house = director.constructHouse();
    
            //重置建造者
            HighHouse highHouse = new HighHouse();
            director.setHouseBuilder(highHouse);
            House house1 = director.constructHouse();
        }
    }
    

    上面代码总结起来:一是要把房子归为房子,有属性就够了,建造归建造,相当于是建筑工人,和房子两个对象分开,那么Director相当于包工头,对于不同的House要指挥不一样的Builder群体。


    二、建造者模式在JDK中的应用


    java.lang.StringBuilder类,也就是常用的可变字符串类,用到的就是建造者模式。以其中的常用方法 append 方法为例看源码。

    2.1 Appendable 接口

    定义了多个 append 方法(抽象方法),即 Appendable 就是我们的抽象建造者Builder 。

    2.2 具体的实现类 AbstractStringBuilder

    虽然也是一个抽象类,但是也已经实现了 Append able 接口的方法,所以其实相当于是具体的建造者ConcreteBuilder了;

    2.3 StringBuilder,继承了AbstractStringBuilder

    但是他重写 append 方法的方式只是调用了父类方法,所以应该说,StringBuilder既充当了Director,又是一个ConcreteBuilder.


    三、注意事项


    1. 客户端不必知道产品呢内部组成的细节,将产品本身和产品的创建过程解耦,使得相同的创建过程可以创建不同的产品;
    2. 每一个具体的建造者都是相对独立的,和其他的建造者无关,因此可以方便替换具体建造者或者增加新的具体建造者,用户使用不同的具体建造者就能得到不同产品;
    3. 可以更加精细的控制创建过程;
    4. 增加新的具体建造者无需修改原有代码,指挥者针对抽象建造者编程;
    5. 建造者模式创建的产品,一定是共同点比较多,组成部分相似,如果产品之间的差异性很大,那么就不适合使用建造者模式,因此其适用范围受到一定的限制。

    建造者模式 VS 抽象工厂模式:

    抽象工厂模式实现对产品家族的创建,一个产品家族:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产。

    建造者模式是按照指定的要求创造产品,主要目的是通过组装零件产生一个新产品。

    (可能有点模糊,但是个人认为本来就是模糊的。。只是一种设计思想,没有严格的边界。。。)
    多多理解,就会清楚的!

  • 相关阅读:
    Codeforces Round #260 (Div. 1) A
    cdoj 1131 男神的礼物 区间dp
    bzoj2435: [Noi2011]道路修建 树上dp
    hdu 4597 Play Game 区间dp
    cdoj 31 饭卡(card) 01背包
    hdu5256 序列变换 dp LIS
    BZOJ 4027: [HEOI2015]兔子与樱花 树上dp
    Codeforces Round #202 (Div. 1) D. Turtles dp
    hdu 4114 Disney's FastPass 状压dp
    Python help() 函数
  • 原文地址:https://www.cnblogs.com/lifegoeson/p/13500365.html
Copyright © 2011-2022 走看看