经典Builder/变种Builder模式及自动化生成代码插件
Builder模式是一种广泛使用的设计模式。
将一个复杂对象的构建与它的表示分立,这样在调用相同构建的过程中可以创建不同的表示
Builder模式分二种,一种是经典的Builder模式,第二种是变种Builder模式,而现在Android开发普遍使用的是第二种的变种Builder模式,下面我们一一来介绍。
---------------------------------我是分割线,不分不舒服------------------------
经典的Builder模式
经典Buider模式分为四块:
- Product:被构造的复杂对象。
- Builder:抽象接口。
- BuilderImpl:抽象接口的具体实现。
- Director:接口的构造者和使用者。
举个最简单的例子。
现在有个厂要生产不同的饼干,有方形的,圆形的等。
我们先建立饼干的类
public class Cookies {
private String shape;
public String getShape(){
return shape;
}
public void setShape(String shape){
this.shape = shape;
}
}
然后我们创建Builder接口
public interface Builder{
public void setShape();
public Cookies getCookies();
}
然后实现Builder接口,比如创建一个会建立方形饼干的SquareCookiesBuilder和一个会建立圆形饼干的RoundCookiesBuilder
public class SquareCookiesBuilder implements Builder{
private Cookies cookies;
@Override
public SquareCookiesBuilder(){
this.cookies = new Cookies();
}
@Override
public void setShape(){
this.cookies.setShape("方形");
}
@Override
public Cookies getCookies(){
return this.cookies;
}
}
public class RoundCookiesBuilder implements Builder{
private Cookies cookies;
@Override
public RoundCookiesBuilder(){
this.cookies = new Cookies();
}
@Override
public void setShape(){
this.cookies.setShape("圆形");
}
@Override
public Cookies getCookies(){
return this.cookies;
}
}
最后创建Director类
public class Director {
private Builder builder;
public Director(Builder builder){
this.builder = builder;
}
public void createCookies(){
this.builder.setShape()
}
public Cookies getCookies(){
return this.builder.getCookies();
}
}
这样就是
比如获取方形的饼干
new Director(new SquareCookiesBuilder()).createCookies().getCookies()
比如获取圆形的饼干。
new Director(new RoundCookiesBuilder()).createCookies().getCookies()
二者的区别就是对Director传入不同形状饼干的Builder的实现类。
而Director的对象调用的方法都是createCookies()和getCookies()
所以经典的Builder模式重点在于抽象出对象创建的步骤,并通过调用不同的具体实现类从而得到不同的结果,而变种的Builder模式的目的在于减少对象创建过程中引入的多个重载构造函数,可选参数以及setters过度使用导致的不必要的复杂性
--------------------------我是变种分割线O(∩_∩)O~----------------------------
变种Builder模式
我们一步步来。比如还是Cookies举例。就单纯的还是形状。
public class Cookies {
private final String shape;
}
(一般来说,我们尽量将属性值定义为不可变的。总不能饼干都已经做成方的了。再把它改成圆形吧)
那这时候怎么对这个shape赋值呢。你可能会想到
- 构造函数
因为参数是final类型了。所以必须在构造函数中进行初始化,否则不能编译通过
public class Cookies {
private final String shape;
pubic class Cookies(String shape){
this.shape = shape;
}
}
这样看是没问题。但是如果我们不是饼干,是一个人:Person类。它有name,gender,age三个属性。但是用户并不是要每个属性都要输入的。这时候就要建立多个构造函数。
public class Person {
private final String name;
private final String gender;
private final String age;
pubic class Person(String name){
this(name,"男","20");
}
pubic class Person(String name,String gender){
this(name,gender,"20")
}
pubic class Person(String name,String gender,String age){
this.name = name;
this.gender = gender;
this.age = age;
}
}
这种构造函数虽然简单,但是当属性多了的时候。代码就会变得不易维护,而且构造函数里面的参数的顺序也很容易弄错。当参数有五个。你还记得第几个参数要填年龄?记得第几个参数要填姓名?
- getters 和 setters 函数
public class Cookies {
private String shape;
public void setShape(String shape){
this.shape = shape;
}
public String getShape(){
return this.shape;
}
}
优点:你可以建立对象,然后对你想要修改的属性进行修改,比如有二个属性,你可以只要调用你想修改的属性的set方法就可以进行修改。
缺点:
1.因为是set方法,所以shape的参数不在是final修饰了,因为你本身可以多次调用set方法。这样Cookies类就变成可变类了。失去了不可变类的好处了。
2.比如刚那个Person类,有三个属性。当你要给它的对象赋值这三个属性的时候,就要
Person person = new Person();
person.setName("青蛙ing");
person.setAge("20");
person.setGender("男");
失去一种连贯的感觉,而且这还只有三个属性。要是10个。你这样一行行的set方法写十遍??
----------------------我是主角分割线(我是主角!!)--------------------
还是以上面的Person类为例子。
public class Person {
private final String name;
private final String gender;
private final String age;
private Person(Builder builder) {
name = builder.name;
gender = builder.gender;
age = builder.age;
}
public String getName() {
return name;
}
public String getGender() {
return gender;
}
public String getAge() {
return age;
}
public static final class Builder {
private String name;
private String gender;
private String age;
public Builder() {
}
public Builder name(String val) {
name = val;
return this;
}
public Builder gender(String val) {
gender = val;
return this;
}
public Builder age(String val) {
age = val;
return this;
}
public Person build() {
return new Person(this);
}
}
}
从上述代码可以看出:
1.Person类的构造函数是私有的。这样就不能直接实例化这个类
2.Person类是不可变的。里面的属性都是final的。只能在构造函数中初始化。然后提供了属性的get函数,可以去获取值。
3.连贯性,这个Person的创建是:
new Person.Builder().name("青蛙ing").gender("男").age("20").build();
就问你这么写爽不爽。!!
------------------------------我是插件介绍线------------------------------------
这一段我就不自己截图了。
就引用别人的插件介绍了。
感谢CSDN的拭心
从他的文章里面拿了插件介绍的图片和内容
http://blog.csdn.net/u011240877/article/details/53248917
变种Builder模式自动化生成
1.下载插件 InnerBuilder:
2.重启 Andriod Studio;
3.写好要构建的类的变量:
比如:
public class PersonTest {
private final String mName;
private int mAge;
private String mLocation;
}
4.按 Control + Insert (Mac :command + N):
5.在弹出的 Generate 对话框中选择 Builder:
6.选中要使用 Builder 构建的对象,然后勾选使用的配置,点击OK
public class PersonTest {
private final String mName;
private int mAge;
private String mLocation;
private PersonTest(Builder builder) {
mName = builder.mName;
mAge = builder.mAge;
mLocation = builder.mLocation;
}
public static final class Builder {
private String mName;
private int mAge;
private String mLocation;
public Builder() {
}
public Builder mName(String mName) {
this.mName = mName;
return this;
}
public Builder mAge(int mAge) {
this.mAge = mAge;
return this;
}
public Builder mLocation(String mLocation) {
this.mLocation = mLocation;
return this;
}
public PersonTest build() {
return new PersonTest(this);
}
}
}