关于java:设计模式4-建造者模式详解

30次阅读

共计 6274 个字符,预计需要花费 16 分钟才能阅读完成。

开局一张图,剩下全靠写 …

<img src=”https://markdownpicture.oss-cn-qingdao.aliyuncs.com/blog/ 设计模式.png” style=”zoom: 33%;” >

引言

设计模式汇合:http://aphysia.cn/categories/…

如果你用过 Mybatis,置信你对以下代码的写法并不生疏, 先创立一个 builder 对象,而后再调用 .build() 函数:

InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();

下面其实就是咱们这篇文章所要解说的 建造者模式, 上面让咱们一起来推敲一下它。

什么是建造者模式

建造者模式是设计模式的一种,将一个简单对象的构建与它的示意拆散,使得同样的构建过程能够创立不同的示意。(来源于百度百科)

建造者模式,其实是创立型模式的一种,也是 23 种设计模式中的一种,从下面的定义来看比拟含糊,然而不得不抵赖,当咱们有能力用简洁的话去定义一个货色的时候,咱们才是真的理解它了,因为这个时候咱们曾经晓得它的界线在哪。

所谓将一个简单对象的构建与它的示意拆散,就是将对象的构建器形象进去,结构的过程一样,然而不一样的结构器能够实现不一样的示意。

构造与例子

建造者模式次要分为以下四种角色:

  • 产品(Product):具体生产器要结构的简单对象
  • 形象生成器(Bulider):形象生成器是一个接口,创立一个产品各个部件的接口办法,以及返回产品的办法
  • 具体建造者(ConcreteBuilder): 依照本人的产品个性,实现形象建造者对应的接口
  • 指挥者(Director): 创立一个简单的对象,管制具体的流程

说到这里,可能会有点懵,毕竟全都是定义,上面从理论例子来讲讲,就拿程序员最喜爱的电脑来说,假如当初要生产多种电脑,电脑有屏幕,鼠标,cpu,主板,磁盘,内存等等,咱们可能立马就能写进去:

public class Computer {
    private String screen;
    private String mouse;
    private String cpu;
    private String mainBoard;
    private String disk;
    private String memory;
      ...
    public String getMouse() {return mouse;}

    public void setMouse(String mouse) {this.mouse = mouse;}

    public String getCpu() {return cpu;}

    public void setCpu(String cpu) {this.cpu = cpu;}
      ...
}

下面的例子中,每一种属性都应用独自的 set 办法, 要是生产不同的电脑的不同部件,具体的实现还不太一样,这样一个类实现起来貌似不是很优雅,比方联想电脑和华硕电脑的屏幕的构建过程不一样,而且这些部件的构建,实践上都是电脑的一部分,咱们能够思考 流水线式 的解决。

当然,也有另外一种实现,就是多个构造函数,不同的构造函数带有不同的参数,实现了可选的参数:

public class Computer {
    private String screen;
    private String mouse;
    private String cpu;
    private String mainBoard;
    private String disk;
    private String memory;

    public Computer(String screen) {this.screen = screen;}

    public Computer(String screen, String mouse) {
        this.screen = screen;
        this.mouse = mouse;
    }

    public Computer(String screen, String mouse, String cpu) {
        this.screen = screen;
        this.mouse = mouse;
        this.cpu = cpu;
    }
      ...
}

下面多种参数的构造方法,实践上满足了按需结构的要求,然而还是会有有余的中央:

  • 假使结构每一个部件的过程都比较复杂,那么构造函数看起来就比拟凌乱
  • 如果有多种按需结构的要求,构造函数就太多了
  • 结构不同的电脑类型,耦合在一块, 必须形象进去

首先,咱们先用流水线的形式,实现按需结构,不能重载那么多构造函数:

public class Computer {
    private String screen;
    private String mouse;
    private String cpu;
    private String mainBoard;
    private String disk;
    private String memory;

    public Computer setScreen(String screen) {
        this.screen = screen;
        return this;
    }

    public Computer setMouse(String mouse) {
        this.mouse = mouse;
        return this;
    }

    public Computer setCpu(String cpu) {
        this.cpu = cpu;
        return this;
    }

    public Computer setMainBoard(String mainBoard) {
        this.mainBoard = mainBoard;
        return this;
    }

    public Computer setDisk(String disk) {
        this.disk = disk;
        return this;
    }

    public Computer setMemory(String memory) {
        this.memory = memory;
        return this;
    }
}

应用的时候,结构起来,就像是流水线一样,一步一步结构就能够:

        Computer computer = new Computer()
                .setScreen("高清屏幕")
                .setMouse("罗技鼠标")
                .setCpu("i7 处理器")
                .setMainBoard("联想主板")
                .setMemory("32G 内存")
                .setDisk("512G 磁盘");

然而以上的写法不够优雅,既然结构过程可能很简单,为何不必一个特定的类来结构呢?这样结构的过程和主类就拆散了,职责更加清晰,在这里外部类就能够了:

package designpattern.builder;

import javax.swing.*;

public class Computer {
    private String screen;
    private String mouse;
    private String cpu;
    private String mainBoard;
    private String disk;
    private String memory;

    Computer(Builder builder) {
        this.screen = builder.screen;
        this.cpu = builder.cpu;
        this.disk = builder.disk;
        this.mainBoard = builder.mainBoard;
        this.memory = builder.memory;
        this.mouse = builder.mouse;
    }

    public static class Builder {
        private String screen;
        private String mouse;
        private String cpu;
        private String mainBoard;
        private String disk;
        private String memory;

        public Builder setScreen(String screen) {
            this.screen = screen;
            return this;
        }

        public Builder setMouse(String mouse) {
            this.mouse = mouse;
            return this;
        }

        public Builder setCpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public Builder setMainBoard(String mainBoard) {
            this.mainBoard = mainBoard;
            return this;
        }

        public Builder setDisk(String disk) {
            this.disk = disk;
            return this;
        }

        public Builder setMemory(String memory) {
            this.memory = memory;
            return this;
        }

        public Computer build() {return new Computer(this);
        }
    }
}

应用的时候,应用 builder 来构建,构建实现之后,调用 build 的时候,再将具体的值,赋予咱们须要的对象(这里是Computer):

public class Test {public static void main(String[] args) {Computer computer = new Computer.Builder()
                .setScreen("高清屏幕")
                .setMouse("罗技鼠标")
                .setCpu("i7 处理器")
                .setMainBoard("联想主板")
                .setMemory("32G 内存")
                .setDisk("512G 磁盘")
                .build();
        System.out.println(computer.toString());
    }
}

然而下面的写法,如果咱们结构多种电脑,每种电脑的配置不太一样,构建的过程也不一样,那么咱们就必须将结构器形象进去,变成一个抽象类。

首先咱们定义产品类Computer

public class Computer {
    private String screen;
    private String mouse;
    private String cpu;

    public void setScreen(String screen) {this.screen = screen;}

    public void setMouse(String mouse) {this.mouse = mouse;}

    public void setCpu(String cpu) {this.cpu = cpu;}

    @Override
    public String toString() {
        return "Computer{" +
                "screen='" + screen + '\'' +
                ", mouse='" + mouse + '\'' +
                ", cpu='" + cpu + '\'' +
                '}';
    }
}

定义一个形象的结构类,用于所有的电脑类结构:

public abstract class Builder {abstract Builder buildScreen(String screen);
    abstract Builder buildMouse(String mouse);
    abstract Builder buildCpu(String cpu);

    abstract Computer build();}

先结构一台联想电脑,那联想电脑必须实现本人的结构器,每一款电脑总有本人非凡的中央:

public class LenovoBuilder extends Builder {private Computer computer = new Computer();

    @Override
    Builder buildScreen(String screen) {computer.setScreen(screen);
        return this;
    }

    @Override
    Builder buildMouse(String mouse) {computer.setMouse(mouse);
        return this;
    }

    @Override
    Builder buildCpu(String cpu) {computer.setCpu(cpu);
        return this;
    }

    @Override
    Computer build() {System.out.println("构建中...");
        return computer;
    }
}

构建器有了,还须要有个指挥者,它负责去构建咱们具体的电脑:

public class Director {
    Builder builder = null;
    public Director(Builder builder){this.builder = builder;}
    
    public void doProcess(String screen,String mouse,String cpu){builder.buildScreen(screen)
                .buildMouse(mouse)
                .buildCpu(cpu); 
    }
}

应用的时候,咱们只须要先构建 builder,而后把builder 传递给指挥者,他负责具体的构建,构建完之后,构建器调用一下 .build() 办法,就能够创立出一台电脑。

public class Test {public static void main(String[] args) {LenovoBuilder builder = new LenovoBuilder();
        Director director = new Director(builder);
        director.doProcess("联想屏幕","游戏鼠标","高性能 cpu");
        Computer computer = builder.build();
        System.out.println(computer);
    }
}

打印后果:

构建中...
Computer{screen='联想屏幕', mouse='游戏鼠标', cpu='高性能 cpu'}

以上其实就是残缺的建造者模式,然而咱们平时用的,大部分都是本人间接调用构建器Builder,一路set(),最初build(),就创立出了一个对象。

应用场景

构建这模式的益处是什么?首先想到的应该是将构建的过程解耦了,构建的过程如果很简单,独自拎进去写,清晰简洁。其次,每个局部的构建,其实都是能够独立去创立的,不须要多个构造方法,构建的工作交给了构建器,而不是对象自身。业余的人做业余的事。同样,构建者模式也比拟实用于不同的构造方法或者结构程序,可能会产生不同的结构后果的场景。

然而毛病还是有的,须要保护多进去的 Builder 对象,如果多种产品之间的共性不多,那么形象的构建器将会失去它该有的作用。如果产品类型很多,那么定义太多的构建类来实现这种变动,代码也会变得比较复杂。

最近在公司用GRPC,外面的对象简直都是基于构建者模式,链式的构建的确写着很难受,也比拟优雅,代码是写给人看的,咱们所做的所有设计模式,都是为了拓展,解耦,以及防止代码只能口口相传。

【作者简介】
秦怀,公众号【秦怀杂货店 】作者,技术之路不在一时,山高水长,纵使迟缓,驰而不息。集体写作方向:Java 源码解析JDBCMybatisSpringredis 分布式 剑指 OfferLeetCode等,认真写好每一篇文章,不喜爱题目党,不喜爱花里胡哨,大多写系列文章,不能保障我写的都完全正确,然而我保障所写的均通过实际或者查找材料。脱漏或者谬误之处,还望斧正。

剑指 Offer 全副题解 PDF

2020 年我写了什么?

开源编程笔记

正文完
 0