zoukankan      html  css  js  c++  java
  • 设计模式之建造者(Builder)模式

    设计模式之建造者(Builder)模式

      存在一些情况,比如,一些对象会有一些重要的属性,在这些属性没有恰当的值之前,对象不能作为一个完整的产品使用(如一个电子邮件最起码得有收件人地址);还有一些些情况,一个对象的一些属性必须按照一定的顺序赋值才有意义,在某个属性没有赋值之前,另一个属性则无法赋值。Builder模式非常适用于此种类型的情况。

      (一)什么是Builder模式

      Builder模式是一种对象创建模式,用来隐藏复合对象的创建过程。建造者模式利用一个导演者(Director)对象和具体构造者(Concrete Builder)对象一个一个地建造出所有属性(零件),从而建造出完整的产品对象。建造者模式将产品的结构和产品的零件建造过程对客户端隐藏起来,把对建造过程进行指挥的责任和具体建造者零件的责任分割开来,达到责任划分和封装的目的。

      (二)Builder模式中的角色

      抽象建造者(Builder)角色:给出一个抽象接口,以规范产品对象的各个组成部分的建造。一般此接口独立于应用程序的商业逻辑。这个接口一般包含两种方法,创建方法和返回方法。

      具体建造者(ConcreteBuilder)角色:它必须实现创造者Builder所声明的接口,在创在完成后,提供产品实例。一般来说,每有一个具体产品,就有一个相应的具体建造类。

      导演者(Director)角色:担任这个角色的类调用具体建造者角色以创建产品对象。

      产品(Product)角色:产品就是所建造的复杂对象,一个系统中会有多于一个的产品类,这些产品类并不一定有共同的接口,而完全可以是不相互关联的。导演者角色是与客户端打交道的角色,它将客户端创造产品的请求划分为多个零件的建造请求,再将这些请求委派给具体建造者角色,具体建造者角色是做具体建造工作的。

      Builder模式的结构图如下:

     (三)建造者模式的具体实现

      想象一下,有这样一种业务场景:客户端向要建造一所房子 (可以是平房,也可以是公寓),房子由多个组件构成,包括地板、墙和天花板等,从程序的角度出发,能有哪些解决方案呢?

        1)客户端自己创建房子。

        2)客户端委托具体工程队建造房子

        3)客户端寻找设计师,并给设计师配备工程队建造房子 。

      (1)客户端自己建造房子。

      客户端自己创建房子的各个组件,如果建造平房就用相应的平房地板、墙、天花板

          House house = new House();
          house.setFloor("地板");
          house.setWall("墙");
          house.setCeil("天花板");

      (2)客户端委托工程队创建房子 

      客户端委托工程队建造房子 ,如果要建造平房,就选择建造平房的工程队,如果建造公寓,就选择建造公寓的工程队。

            HouseBuilder builder = new PingFangBuilder();
            builder.makeFloor();
            builder.makeWall();
            builder.makeCeil();
            House pingFang = builder.getHouse();        

      貌似这种方式,看起来已经比较完美,有点面向对象的意思。但仍存在缺点,封装不够,房子具体部件的创建仍然暴露在客户端(在这里可以理解为建造房子的时候,还需要需要客户端进行督工),倘若需要满足这样一种对象创建逻辑:必须按照地板、墙、天花板的顺序建造房子,在客户端创建容易出错。此时,这种方式创建对象不能满足要求,第三种方式却能满足。

      (3)客户端寻找设计师,并给设计师配备工程队建造房子 

      客户端委托设计师创建房子,房子各个组件的创建顺序可以在设计师中具体指定,具体的建造仍然交给工程队,只要工程队的调度交给设计者,也可以称为管理者。这样设计者就需要一个具体的工程队,可以选择两种方式:1)每个设计师包含一个工程队属性。2)给设计师的相应方法传入一个具体 工程队。在这里我们选择第二种方式。

      以上叙述中,房子扮演者Product的角色,设计师扮演Director角色,工程队扮演Builder角色,而具体工程队(包括平房工程队和公寓工程队)扮演ConcreteBuilder角色。具体代码实现如下:

      1)Product:House

    /*
     * 房子
     */
    public class House {
        //地板
        private String floor;
        //
        private String wall;
        //屋顶
        private String ceil;
        public String getFloor() {
            return floor;
        }
        public void setFloor(String floor) {
            this.floor = floor;
        }
        public String getWall() {
            return wall;
        }
        public void setWall(String wall) {
            this.wall = wall;
        }
        public String getCeil() {
            return ceil;
        }
        public void setCeil(String ceil) {
            this.ceil = ceil;
        }
    }

      2)抽象建造者:HouseBuilder

    public interface HouseBuilder {
        //修地板
        public void makeFloor();
        //修墙
        public void makeWall();
        //修天花板
        public void makeCeil();
        
        //返回房子
        public House getHouse();
    }

      3)具体建造者:PingFangBuilder、ApartmentBuilder

    public class PingFangBuilder implements HouseBuilder {
        private House house =  new House();
        @Override
        public void makeFloor() {
            house.setFloor("平房---房顶");
        }
    
        @Override
        public void makeWall() {
            house.setWall("平房---墙");
        }
    
        @Override
        public void makeCeil() {
            house.setCeil("平房---天花板");
        }
    
        @Override
        public House getHouse() {
            return house;
        }
    }
    public class ApartmentBuilder implements HouseBuilder {
        private House house = new House();
        @Override
        public void makeFloor() {
            house.setFloor("公寓---地板");
        }
    
        @Override
        public void makeWall() {
            house.setWall("公寓---墙");
        }
    
        @Override
        public void makeCeil() {
            house.setCeil("公寓---天花板");
        }
    
        @Override
        public House getHouse() {
            return house;
        }
    
    }

      4)DIrector:HouseDirector

    public class HouseDirector {
        public House constructHouse(HouseBuilder builder) {
            builder.makeFloor();
            builder.makeWall();
            builder.makeCeil();
            return builder.getHouse();
        }
    }

       5)Client

    HouseBuilder builder1 = new PingFangBuilder();
    HouseDirector director1 = new HouseDirector();
    House pingFang = director1.constructHouse(builder1);
            
    HouseBuilder builder2 = new ApartmentBuilder();
    HouseDirector director2 = new HouseDirector();
    House apartment = director2.constructHouse(builder2);

      (四)什么情况下使用建造模式

       需要生成的产品对象有复杂的内部结构,。

      需要生成的产品对象的属性相互依赖,即一个属性必须在一个属性被赋值后才可以被赋值。

      在对象创建过程中,会使用系统的其他一些对象,这些对象在产品创建的过程中不易得到。

      (五)抽象工厂模式和Builder模式的区别: 

      二者都是对象创建模式,在抽象工厂模式中,每调用一次工厂对象,都会返回一个完整的产品对象,客户端可能会把这些产品组装成一个更大更复杂的产品,也可能不会。建造者模式则不同,它一点一点地构造出一个复杂的产品,而这个产品的组装过程就发生在建造者角色内部,建造者模式的客户端拿到的是一个完成的产品。

      也就是说,建造者模式处于更加宏观的尺度上,而建造者模式处于更加具体的尺度上。建造者模式所创建产品的零部件可由抽象工厂创建完成。

  • 相关阅读:
    centos 7 pip install MySQL-python 报错
    修改centos history记录数上限
    CentOS 7 如何设置为eth0网卡
    字符串判空有空格报错:binary operator expected
    Linux指定用户运行程序
    MySQL 新建用户,为用户授权,指定用户访问数据库
    解决linux 中文乱码
    UNIX目录访问操作
    通过lseek产生空洞文件
    lseek系统调用
  • 原文地址:https://www.cnblogs.com/gdy1993/p/9193374.html
Copyright © 2011-2022 走看看