• 设计模式-----Builder模式


    前言

    近日,看到Myabtis中组件中SqlSessionFactory由SqlSessionFactoryBuilder().build()生成时,且采用Builder模式,遂记录学习之。

    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    1、什么是Builder模式?

      (1)对于复杂的对象,如果只是用构造方法创建的话,构造方法中会存在很多的逻辑,那么我们可以一步步有秩序构建它,从而降低复杂度;

      (2)对于复杂的对象,使用者不必知道其内部是如何实现的清下,逐步构造需要的实例对象;

    2、什么情况下使用Builder模式?

      (1)将一个复杂对象的构建与它的表示分离,即相同的构造过程可以有不同表示;

      (2)当有多个构造器且需要传入不同的参数表示不同的产品时(即可以弥补工厂模式等无法选择多参数的缺点)

      (3)传入参数情况比较灵活且复杂的情况,或者说一开始不需要明确参数的情况。

      (4)框架中很多Configuration配置都会用到Builder模式。

    3、具体使用Builder例子

    (1)以前经常通过不同构造器传入不同的参数构造不同复杂的对象,比如我们现在需要一个User的不同情况对象

    • 只有id和name
    • 有id、name、age
    • 有id、name、age、address
    public class User {
        private int id;
        private String name;
        private int age;
        private String address;
        
        //不同的构造器传入不同的参数,创造不同的复杂的产品
        public User(int id, String name) {
            this.id = id;
            this.name = name;
        }
        public User(int id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
        public User(int id, String name, int age, String address) {
            this.id = id;
            this.name = name;
            this.age= age;
            this.address = address;
        }
        
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }

    测试类这样编写:

    public class Main {
        public static void main(String[] args) {
            //情况1:id、姓名
            User user = new User(1, "Zhangsan");
            //情况2:id、姓名、年龄
            User user2 = new User(2,"Lisi",22);
            //情况3:id、姓名、年龄、地址
            User user3 = new User(3,"Wangwu",23,"Beijing");
            //情况4:id与年龄不清楚,很容易混淆,必须得查看源码或者文档才能知道哪个参数位置id/年龄
            User user4 = new User(24,"Wangwu",24,"Beijing");
        }
    }

    OK,这样是没有问题的,但是会有以下弊端:

    • 就好比情况4。当传入的参数很多并且没有说明文档的情况下,之后阅读完源码后才能更好地使用。那么就有可能对源码进行修改,这样就违背了在应用中一个好的设计模块的原则,即设计模式中的开闭原则(Open-Closed Principle, OCP,对修改封闭)
    • 每种情况都得编写一个的构造器,没有一点的灵活度。再比如这里address属性是可选的,可以不传入,那么灵活度同样很低!

    (2)接下来就使用Builder模式创建,注意:Builder主要采用Java静态内部类

    /**
     * 利用Builer模式灵活面对复杂对象的创建
     * @author Lijian
     *
     */
    public class User2 {
        private int id;
        private String name;
        private int age;
        private String address;
        
        private User2(Builder builder) {
            this.id = builder.id;
            this.name = builder.name;
            this.age = builder.age;
            this.address = builder.address;
        }
        static class Builder{
            private int id;
            private String name;
            private int age;
            private String address;
            //灵活选择参数
            public Builder setId(int id) {
                this.id = id;
                return this;
            }
            public Builder setName(String name) {
                this.name = name;
                return this;
            }
            public Builder setAddress(String address) {
                this.address = address;
                return this;
            }
            public Builder setAge(int age) {
                this.age = age;
                return this;
            }
            //最后build返回User2对象
            public User2 build() {
                return new User2(this);
            }
        }
    }

    测试类:

    public class Main {
        public static void main(String[] args) {
            //通过build创建了User2对象,之后通过setXXX方法可灵活初始化属性,最后build返回对象
            User2 user = new User2.Builder().setId(1).setName("Lijian").setAge(22).build();
            //情况1:id、姓名
            User2 user2 = new User2.Builder().setId(2).setName("Zhangsan").build();
            //情况2:id、姓名、年轻、地址
            User2 user3 = new User2.Builder().setId(2).setName("Lisi").build();
            //情况3:id与age很明显能区分
            User2 user4 = new User2.Builder().setId(23).setAge(23).build();
        }
    }

    通过setXXX()方法灵活选择参数,最后build()方法“闭合”返回对象。很适用于复杂对象的创建,此处让我想起Java8新特性中的Stream API(https://blog.csdn.net/mynewclass/article/details/80393308)的一个特点:懒加载。是的,有点“懒加载”的味道,不需要立马指定属性,也不会立马生效,之后最后的操作build()才会生效!

  • 相关阅读:
    Ansible学习 Playbooks_1
    Ansible学习 ad-hoc命令
    Ansible学习 Patterns
    【转】对于SQL SERVER 事务日志已满问题整理
    【转】Apache配置正向代理与反向代理
    【转】Python的IDE和破解Code——pycharm
    【转】SQLServer 数据库变成单个用户后无法访问问题的解决方法
    【转】 尝试在数据库5 中提取逻辑页() 失败。该逻辑页属于分配单元xxx而非xxx
    【Oracle】Oracle版本导入导出问题
    【Java】eclipse导入war包二次开发
  • 原文地址:https://www.cnblogs.com/jian0110/p/9393573.html
Copyright © 2020-2023  润新知