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

    概述

    建造者模式:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。 [构建与表示分离,同构建不同表示]

    假如一个对象的构建很复杂,需要很多步骤。则可以使用建造者模式,将其构建对象和组装成一个对象这两步给分开来。构建部分为(builder)和组织部分(director),实现了构建和装配的解耦。

    不同的构建器,相同的装配也可以做出不同的对象。

    相同的构建器,不同的装配顺序也可以做出不同的对象。

    UML

    • Dirextor: 指挥者类,用于统一组装流程
    • Builder:抽象Builder类,规范产品的组建,一般是由子类实现。
    • ConcreteBulider: 抽象Builder类的实现类,实现抽象Builder类定义的所有方法,并且返回一个组建好的对象
    • Product: 产品类

    适用场合

    • 相同的方法,不同的执行顺序,产生不同的事件结果时。
    • 多个部件或零件装配到一个对象中,但是产生的运行结果又不同。
    • 产品类非常复杂,或者产品中的调用顺序不同产生不同的作用时,就可以考虑建造者模式。
    • 当初始化一个对象特别复杂,参数多,且很多参数都具有默认值时。

    例子

    以生产PC为例,这里我们假设生产一台PC只需三个步骤,创建cpu、创建内存、创建显示器,将三个步骤抽象成一个Builder,且该Builder有一个创建待加工的产品的方法和返回成品的方法;

    以联想电脑和惠普电脑为例,认为它们在生产电脑的过程中,以上三个步骤的实现是不一致的,对应着具体的HPBuilder和LenovoBuilder;

    同时,我们把电脑产品封装成Computer类,其拥有cpu、内存、显示器三个属性;

    然后,再创建一个指挥者类Director,其拥有一个建造者对象和建造PC产品的方法construct,该方法通过具体建造者对象,依次执行每个步骤,最后返回建造完成的产品对象;

    类图:

    代码实现:

    产品角色

    package com.dyleaf.create.BuilderPattern;
    
    public class Computer {
    
        private String cpu;
        private String ram;
        private String monitor;
        /**
         * @return the cpu
         */
        public String getCpu() {
            return cpu;
        }
        /**
         * @param cpu the cpu to set
         */
        public void setCpu(String cpu) {
            this.cpu = cpu;
        }
        /**
         * @return the ram
         */
        public String getRam() {
            return ram;
        }
        /**
         * @param ram the ram to set
         */
        public void setRam(String ram) {
            this.ram = ram;
        }
        /**
         * @return the monitor
         */
        public String getMonitor() {
            return monitor;
        }
        /**
         * @param monitor the monitor to set
         */
        public void setMonitor(String monitor) {
            this.monitor = monitor;
        }
    
        public String toString(){
            return "PC:" + this.cpu + ", " + this.ram + ", " + this.monitor;
        }
    }
    

    抽象建造者

    package com.dyleaf.create.BuilderPattern;
    
    public abstract class Builder {
        private Computer pc ;
        public abstract void buildCpu();
        public abstract void buildRam();
        public abstract void buildMonitor();
    
    
        public void createComputer(){
            this.pc = new Computer();
        }
        public Computer getComputer(){
            return this.pc;
        }
    }
    

    两个具体建造者

    package com.dyleaf.create.BuilderPattern;
    
    public class LenovoBuilder extends Builder{
        @Override
        public void buildCpu() {
            System.out.println("lenovo: build cpu start...");
            this.getComputer().setCpu("lenovo cpu");
            System.out.println("lenovo: build cpu end...");
        }
    
        @Override
        public void buildRam() {
            System.out.println("lenovo: build ram start...");
            this.getComputer().setRam("lenovo ram");
            System.out.println("lenovo: build ram end...");
    
        }
    
        @Override
        public void buildMonitor() {
            System.out.println("lenovo: build monitor start...");
            this.getComputer().setMonitor("lenovo monitor");
            System.out.println("lenovo: build monitor end...");
    
        }
    }
    
    package com.dyleaf.create.BuilderPattern;
    
    public class HPBuilder extends Builder{
    
        @Override
        public void buildCpu() {
            System.out.println("hp: build cpu start...");
            this.getComputer().setCpu("hp cpu");
            System.out.println("hp: build cpu end...");
        }
    
        @Override
        public void buildRam() {
            System.out.println("hp: build ram start...");
            this.getComputer().setRam("hp ram");
            System.out.println("hp: build ram end...");
    
        }
    
        @Override
        public void buildMonitor() {
            System.out.println("hp: build monitor start...");
            this.getComputer().setMonitor("hp monitor");
            System.out.println("hp: build monitor end...");
    
        }
    
    }
    

    指挥者

    package com.dyleaf.create.BuilderPattern;
    
    public class Director {
    
        private Builder builder;
        public Director(Builder builder) {
            this.builder = builder;
        }
    
        public Computer construct(){
            this.builder.createComputer();
            this.builder.buildCpu();
            this.builder.buildRam();
            this.builder.buildMonitor();
            return this.builder.getComputer();
        }
    
        /**
         * @return the builder
         */
        public Builder getBuilder() {
            return builder;
        }
    
        /**
         * @param builder the builder to set
         */
        public void setBuilder(Builder builder) {
            this.builder = builder;
        }
    }
    

    Test

    package com.dyleaf.create.BuilderPattern;
    
    public class Test {
        public static void main(String[] args) {
            Builder hpBuilder = new HPBuilder();
            Director director = new Director(hpBuilder);
            Computer hpPC = director.construct();
            System.out.println(hpPC.toString());
    
            Builder lenovoBuilder = new LenovoBuilder();
            director.setBuilder(lenovoBuilder);
            Computer lenovoPC = director.construct();
            System.out.println(lenovoPC.toString());
    
        }
    }
    

    运行结果如下,相同的指挥者使用不同的建造者创建了不同的产品:

    优缺点

    优点

    • 使用Builder会导致写两遍相关属性的代码和SETTER方法(Builder中一次,Director中一次),但是代码的可读性和可用性大大提高。
    • 单个builder构建多个对象时Builder参数可在创建期间进行调整,还可以根据对象不同而进行改变。

    缺点

    • 使用Builder模式是肯定会增加代码量的。- 一般需要嵌套到类中,容易忘记给某个属性添加builder支持。

    see source code

  • 相关阅读:
    Python设置桌面壁纸
    youtube-dl使用介绍
    Matlab pcg函数的句柄形式之参数传递
    Sublime 安装支持GBK的插件
    MarkdownPad安装
    ug7.5经常卡死的解决方法
    HM NIS edit打包软件
    UG工程制图
    egg框架中是如何使用MD5加密的 实现用户修改密码 小编在这里献丑了。。。。。
    今天遇到了vue项目中使用Iconfont图标 ,感觉挺实用的 随手记录下。只需简单的6步就可以实现
  • 原文地址:https://www.cnblogs.com/Dyleaf/p/8507030.html
Copyright © 2011-2022 走看看