创建者设计模式

2018-10-09  本文已影响16人  shd踏尽桐影

Builder -创建者设计模式 是一种非常常见的设计模式,在安卓源码和第三方组件中经常可以见到:

边学编写 我将从以下几个方面整理

太长不看版本:
使用场景:当一个类较复杂,创建时候容易出问题或者不便于理解或者较复杂,希望规范化创建的时候使用创建者模式。
使用:对外通过导演类(规范流程)使用一个实现预期接口的建造者(builder)作为参数来进行创建,不同建造者可以创建不同对象,建造者中实现商业逻辑,最后返回一个造好的商品。导演类调用建造者逻辑,返回造好的商品。
优点:规范,对外方便简洁,利于扩展,内部逻辑可以自己把控。
缺点:如果内部逻辑过于复杂,需要创建很多数据类(Builder),得不偿失。

一、概念

(概念这个东西从来都是 开始看的不知所云或者总觉得很鸡肋的话,但是后来对问题有了深入了解就会发现很重要的的总结)
1 定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的展示。
2 Builder模式属于创建型,一步一步将一个复杂对象创建出来,允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程。

二、使用场景,案例

当我们阅读android源码时候会经常看到创造者模式,如常见的Dialog的创建

new AlertDialog.Builder(context)
.setIcon(R.drawable.navigation_empty_icon).
create();

而在我们实际工作中也经常会遇到这样需求:
由于业务需要创建一个很复杂的类的时候,需要多次创建一个类,并挨个对其属性进行赋值,在创建过程中往往还需要加入只有自己重读都费力的逻辑顺序,这样的代码无疑是十分丑陋和不规范的。而创建者设计模式可以解决这样的问题,那么我们根据什么条件来判断是否应该使用创建者设计模式呢?

这里使用另外一个例子进行讲解。
如一个学生类 由基本属性(年龄、姓名) 成绩属性(各科分数,总分数由各课分数之和得到 )

public class Student {
    传统方法
    private String name;
    private int age;
    private int totleGrade;
    private int mathGrade;
    private int chineseGrade;
     // 等等 …… 
}

传统方法
当我们需要创建这样一个对象时一般方法是2种: 1创建一个空对象使用set方法设置属性,2使用带参数构造方法传入参数。

Student student = new Student();
student.setName("张三");
student.setAge(12);
……

或者

public Student(String name, int age, ……){
this.name = name;
this.age = age;
……
}

这两种方法在数据量少并且逻辑简单的时候使用并没有什么问题,但是当我们成员多创建逻辑复杂时(比如总成绩为各科成绩之和),会增加学习成本并且不利于代码阅读和维护。

下面我们了解一下创建者模式:
创建者模式
1、Builder:给出一个抽象接口,规范建造者对于生产的产品的各个组成部分的建造。这个接口只是定一个规范,不涉及具体的建造,具体的建造让继承于它的子类(ConcreteBuilder)去实现。
2、ConcreteBuilder:实现builder接口,针对不同的商业逻辑,具体化各对象部分的建造,最后返回一个建造好的产品。
3、Director:导演,顾名思义,负责规范流程之用。在指导中不涉及产品的创建,只负责保证复杂对象各部分被创建或按某种顺序创建。
4、Product:复杂对象。
按照惯例,给出建造者模式的UML图(这个先记下来,非常有用,学一个设计模式,先把这个图记下来!)

创建者UML图

简单理解一下就是:

导演(Diector)根据大纲(Builder)写好的剧本(ConcreteBuilder) 拍出作品(Product)。

//1、Builder:给出一个抽象接口,规范建造者对于生产的产品的各个组成部分的建造。
// 这个接口只是定一个规范,不涉及具体的建造,具体的建造让继承于它的子类(ConcreteBuilder)去实现。
public interface Builder {
    void setName(); 
    void setAge();  
    void setMathGrade();    
    void setChineseGrade(); 
    Student build();
}
//ConcreteBuilder:实现builder接口,针对不同的商业逻辑,
// 具体化各对象部分的建造,最后返回一个建造好的产品。
public class BuilderXiaoZhang implements Builder {

    private Student student = new Student();

    @Override
    public void setName() {
        student.setName("xiaoZhang");
    }


    public void setAge() {
        student.setAge(14);
    }

    @Override
    public void setMathGrade() {
        student.setMathGrade(99);
    }


    public void setChineseGrade() {
        student.setChineseGrade(100);
    }

    @Override
    public Student build() {
        return student;
    }

}


//Product:复杂对象。
public class Student {
    private String name;
    private int age;
    private int mathGrade;
    private int chineseGrade;

   //省略setxxx() getxxx()方法
    public Student() {
    }
}

    //Director:导演,顾名思义,负责规范流程之用。
    //在指导中不涉及产品的创建,只负责保证复杂对象各部分被创建或按某种顺序创建。
    public class StudentRegistrar {
        private Builder builder;

        public StudentRegistrar(Builder builder) {
            this.builder = builder;
        }
        //产生产品,这里控制逻辑、顺序
        public Student construct(){
            builder.setName();
            builder.setAge();
            builder.setChineseGrade();
            builder.setMathGrade();
           return builder.build();
        }
    }

使用方法为

BuilderXiaoZhang builderXiaoZhang = new BuilderXiaoZhang();
Student stuZhang = new StudentRegistrar(builderXiaoZhang).construct();

我们可以看到导演类(StudentRegistrar )通过创建方法(construct())控制了复杂对象的赋值,外部调用者只需要创建合适的数据类(实现Builder接口)就可以实现复杂对象的创建。
契合了创建者设计模式的理念:

   public class Student {
        private String name;
        private int age;
        private int mathGrade;
        private int chineseGrade;

        //私有构造方法
        private Student() {
        }

        //builder接口 规范需要实现必要方法
        public interface Builder {
            Builder setName(String name);

            Builder setAge(int age);

            Builder setMathGrade(int mathGrade);

            Builder setChineseGrade(int chineseGrade);

            Student build();
        }

        //静态内部类
        public static class BuilderContrete implements Builder {
            private Student student;

            public BuilderContrete() {
                student = new Student();
            }


            @Override
            public Builder setName(String name) {
                student.name = name;
                return this;
            }

            @Override
            public Builder setAge(int age) {
                student.age = age;
                return this;
            }

            @Override
            public Builder setMathGrade(int mathGrade) {
                student.mathGrade = mathGrade;
                return this;
            }

            @Override
            public Builder setChineseGrade(int chineseGrade) {
                student.chineseGrade = chineseGrade;
                return this;
            }

            //返回设计结果类
            @Override
            public Student build() {
                return student;
            }
        }
    }

使用如下方法既可获得学生类

Student stu = new Student.BuilderContrete()
.setName("张三")
.setAge(14)
.build();

简单理解一下就是 小成本电影:

导演(Diector)自己写剧本(ConcreteBuilder)不要大纲(Builder)直接拍摄出作品(Product);

这样即满足了创建对象的灵活性,也在一定程度上节约了学习创建成本,链式的创建方法也清晰明了。

三.对比优缺点,总结

优点

缺点

不知别人怎么看待设计模式,我初看的时候仅仅感觉大部分是条条框框感觉将原本简单问题复杂化了,后来在看过很多优秀的代码后感觉自己代码在可读性、安全性、规范性等方面种种不足,渐渐理解优雅的代码,不仅仅是靠业务代码逻辑的缜密还有标准的命名锁紧等代码规范,而设计模式就是代码思想的规范,是有效而且必要的。

一直希望写点技术博客,今天算开了个头,希望自己坚持下去。最后如果有什么说的不对的地方,也希望大家指正。

上一篇 下一篇

猜你喜欢

热点阅读