美文网首页
Java设计模式之-建造者模式(Builder)

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

作者: Mock2052 | 来源:发表于2017-12-05 00:40 被阅读0次

    关于建造者模式(或者又叫构造者模式),我在网上看了很多文章。其中不乏很多人直接把建造者模式等同于builder构造器。我想说这是两种完全不同的层次和方向,一种是从系统设计层面考虑的设计模式,用于使整个系统构件间解耦更加明显,更易于扩展;另一种则是为了让构造器能适应多个参数而出现的构造函数变体。
    这里不再对网上漫天的Builder构造器进行解释,只针对建造者模式进行讨论。

    建造者模式:将类的使用者与类的建造方式解耦,将类的使用者与类的建造者解耦。

    当然,上面这句话也是我个人对建造者模式的理解。建造者模式就是实现了三点之间的解耦:类的使用者、类的建造者、类的建造方式
    我们先来看一下建造者模式的示意类图:

    建造者模式
    • Builder, 抽象建造者,定义了建造一个类(Product)需要实现的方法;
    • ConcreteBuilder,具体建造者,实现了抽象建造者定义的方法;
    • Product,产品,其实就是建造者需要建造的东西;
    • Director,其实它才是真正的类的建造者,上面所说的Builder,其实只是定义了类的建造方式,但是真正和类的使用者交互的是Director,它作为具体类的提供者,完成了建造的步骤。

    OK, 我们现在来从上面说的两个解耦进行后续的解释。


    将类的使用者与类的建造方式解耦

    平常我们想进行一个类的构造会怎么写?一般来说我们先new一个实例出来,然后对各个变量进行set,最后做我们想做的事情。这里大家也可以换成直接在构造函数里面传入参数,大致意思是一样的。

    Foo foo = new Foo();
    foo.setA(123);
    foo.setB("abc");
    foo.setC(new bar());
    foo.doSomething();
    

    但是这种做法,实际上将类的初始化和各项配置工作都移交给了类的使用者来做,大大增强了类的使用者和类的建造方式之间的耦合关系,类的使用者必须完全了解如何建造这个类才可以,否则便等不到一个功能完好的实例,更不要说正确地使用了。

    OK,那如果说我现在有这样一个产品类,会被别人使用到。我们先假设产品类是这个样子:

    public class Product {
        private String name;
    
        private BigDecimal price;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public BigDecimal getPrice() {
            return price;
        }
    
        public void setPrice(BigDecimal price) {
            this.price = price;
        }
    }
    

    而我们存在多种建造这个产品的方式,但首先我们需要定义一个接口,用以确定产品的建造者需要做哪些工作:

    public interface IProductBuilder {
        public void giveName();
        public void givePrice();
        public Product build();
    }
    

    而后我们有了两个建造商品的类,一个生产高质量商品,另一个生产普通商品:

    public class HighQualityProductBuilder implements IProductBuilder{
        private Product product = new Product();;
        @Override
        public void giveName() {
            product.setName("A High Quality Product comes out!");
        }
    
        @Override
        public void givePrice() {
            product.setPrice(new BigDecimal("299.99"));
        }
    
        @Override
        public Product build() {
            giveName();
            givePrice();
            refine();
            return product;
        }
    
        private void refine(){
            System.out.println("Don't know how, but the product get refined!");
        }
    }
    
    public class NormalProductBuilder implements IProductBuilder {
        private Product product = new Product();;
    
        @Override
        public void giveName() {
            product.setName("Product with normal quality......");
        }
    
        @Override
        public void givePrice() {
            product.setPrice(new BigDecimal("1.59"));
        }
    
        @Override
        public Product build() {
            giveName();
            givePrice();
            return product;
        }
    }
    

    这个时候我们能够看到,在Builder类中,我已经将值赋给了product的域,并且在build()方法中实现了产品的装配和建造过程。后面会提到,这其实是建造者模式的一大问题所在。

    而后,我们在main方法中模拟使用该类,这样其实就能够实现了将类的使用者与类的建造方式解耦这一目的:

        public static void main(String[] args){
            IProductBuilder builder = new HighQualityProductBuilder();
            Product product = builder.build();
        }
    

    但是到此为止,我们做得还不够。大家可以看到,在类图中展示的Builder、ConcreteBuilder、和Product都已经出现了,但是Director还迟迟不肯露面。下面我们就来说一下Director在整个建造者模式中的作用。


    将类的使用者与类的建造者解耦

    为了实现这一解耦目标,我们引入了Director这个参与者。它主要做的工作,就是封装了Builder,然后直接和外界类的使用者进行交互:

    public class Director {
        private IProductBuilder builder;
        public Director(IProductBuilder builder){
            this.builder = builder;
        }
        
        public Product construct(){
            return builder.build();
        }
    }
    

    而后我们在main方法中使用director来替代原来直接写builder的方式:

        public static void main(String[] args){
            Director director = new Director(new NormalProductBuilder());
            Product product = director.construct();
        }
    

    看到这里,很多人可能会骂我根本就不懂。这不还是写死了NormalProductBuilder了么?不照样是紧耦合了么?有什么意义?其实如果大家写过一点Spring就能顿悟这里面的妙处,只要我在Director构造时使用注入,并将其实现为一个Bean,就可以很轻松地将其进行解耦。由一个Director来作为选择和管理Builder的入口,而通过注入的方式将使用者与后方隔离开来,这才是建造者模式真正强大的地方。

    一大问题

    另外我上面也说了,建造者模式的一大问题,就是它把类的建造过程写死了,绑死了,写成了一套流程化的代码逻辑,不易更改。

    所以说,建造者模式适用于不易变更的且构建复杂的类的实例化场景,而对那些生成过程经常改变的类,则不建议使用该模式,因为得到的收益可能远比不上修改的成本。

    相关文章

      网友评论

          本文标题:Java设计模式之-建造者模式(Builder)

          本文链接:https://www.haomeiwen.com/subject/dxgfixtx.html