builder设计模式适用于,builder模式使用场景

  builder设计模式适用于,builder模式使用场景

  00-1010构建器模式是如何产生的?关于Builder的一点解释了线程安全问题。经典构建器模式的总结。第一次用毕加索的时候,看到下面这个官网例子,我和我的朋友都惊呆了!

  毕加索. with(上下文)。load( http://I . imgur.com/dvpvklr . png )。成(imageView);我被这样简单明了的使用方式和这样灵活的连锁调用深深的迷住了,然后一直在苦苦的追求,但是我的天赋很笨,不知道怎么解除它的神秘。

  对不起,二中病又犯了。让我们再做一次。通过不懈的努力,我终于发现它就是传说中的建设者模型,并学会了如何与它亲密相处。

  00-1010不知道哪位圣人曾经说过,存在就是合理的。Builder模式存在于很多框架和android原生代码中(比如AlertDialog),所以它一定有其解决某些需求的价值。

  考虑这样一个场景,假设有一个类(* * * user * * * *)有很多属性,您希望这些类的属性是不可变的(final),如下面的代码所示:

  public class User { private final String first name;//必需的参数private final String lastName//必需的参数private final int age//可选参数private最终字符串phone//可选参数private最终字符串地址;//可选参数}在这个类中,有些参数是必需的,有些是不必要的。就像注册用户的时候,需要用户的姓和名,而不需要年龄、手机号、家庭住址。那么问题来了,如何创建这个类的对象?

  可行的方案是切实可行的施工方法。第一个构造方法仅包含两个必需参数,第二个构造方法添加一个可选参数,第三个构造方法添加另一个可选参数,依此类推,直到所有参数都包含在构造方法中。

  public User(String firstName,String lastName) { this(firstName,lastName,0);}公共用户(String firstName,String lastName,int age) { this(firstName,lastName,age, );}公共用户(String firstName,String lastName,int age,String phone) { this(firstName,lastName,age,phone, );} public User(String firstName,String lastName,int age,String phone,String address){ this . first name=first name;this.lastName=姓氏;this.age=年龄;this.phone=phonethis.address=地址;}这样只有一个好处:可以成功运行。但是缺点是显而易见的:

  参数少的时候问题不大。一旦参数多了,代码可读性就差了,很难维护。对打电话的人来说也很麻烦。如果我只想再传递一个地址参数,我还必须设置年龄和电话的默认值。而且,调用者会很困惑:我怎么知道第四个字符串参数应该传递给address还是phone?第二个解决方案出现了。我们也可以根据JavaBean的习惯设置一个空参数的构造方法,然后为每个属性设置setters和getters方法。就像下面这样:

  public class User { private String first name;//必需的参数私有字符串lastName//必需的参数private int age//可选参数私有字符串phone//可选参数私有字符串地址;//可选参数public user(){ } public string get first name(){ return fi

  rstName; } public String getLastName() { return lastName; } public int getAge() { return age; } public String getPhone() { return phone; } public String getAddress() { return address; }}这种方法看起来可读性不错,而且易于维护。作为调用者,创建一个空的对象,然后只需传入我感兴趣的参数。那么缺点呢?也有两点:

  对象会产生不一致的状态。当你想要传入5个参数的时候,你必需将所有的setXX方法调用完成之后才行。然而一部分的调用者看到了这个对象后,以为这个对象已经创建完毕,就直接食用了,其实User对象并没有创建完成。****User****类是可变的了,不可变类所有好处都不复存在。终于轮到主角上场的时候了,利用Builder模式,我们可以解决上面的问题,代码如下:

  

public class User { private final String firstName; // 必传参数 private final String lastName; // 必传参数 private final int age; // 可选参数 private final String phone; // 可选参数 private final String address; // 可选参数 private User(UserBuilder builder) { this.firstName = builder.firstName; this.lastName = builder.lastName; this.age = builder.age; this.phone = builder.phone; this.address = builder.address; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } public String getPhone() { return phone; } public String getAddress() { return address; } public static class UserBuilder { private final String firstName; private final String lastName; private int age; private String phone; private String address; public UserBuilder(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public UserBuilder age(int age) { this.age = age; return this; } public UserBuilder phone(String phone) { this.phone = phone; return this; } public UserBuilder address(String address) { this.address = address; return this; } public User build() { return new User(this); } }}

有几个重要的地方需要强调一下:

 

  ****User****类的构造方法是私有的。也就是说调用者不能直接创建User对象。****User****类的属性都是不可变的。所有的属性都添加了final修饰符,并且在构造方法中设置了值。并且,对外只提供getters方法。Builder模式使用了链式调用。可读性更佳。Builder的内部类构造方法中只接收必传的参数,并且该必传的参数适用了final修饰符。相比于前面两种方法,Builder模式拥有其所有的优点,而没有上述方法中的缺点。客户端的代码更容易写,并且更重要的是,可读性非常好。唯一可能存在的问题就是会产生多余的Builder对象,消耗内存。然而大多数情况下我们的Builder内部类使用的是静态修饰的(static),所以这个问题也没多大关系。

  现在,让我们看看如何创建一个User对象呢?

  

new User.UserBuilder("王", "小二") .age(20) .phone("123456789") .address("亚特兰蒂斯大陆") .build();

相当整洁,不是吗?你甚至可以用一行代码完成对象的创建。

 

  

 

  

关于Builder的一点说明

 

  

线程安全问题

由于Builder是非线程安全的,所以如果要在Builder内部类中检查一个参数的合法性,必需要在对象创建完成之后再检查。

 

  

public User build() { User user = new user(this); if (user.getAge() > 120) { throw new IllegalStateException(“Age out of range”); // 线程安全 } return user;}

上面的写法是正确的,而下面的代码是非线程安全的:

 

  

public User build() { if (age > 120) { throw new IllegalStateException(“Age out of range”); // 非线程安全 } return new User(this);}

 

  

经典的Builder模式

上面介绍的Builder模式当然不是原生态的啦,经典的Builder模式的类图如下:

 

  

 

  

builder

  其中:

  Product 产品抽象类。Builder 抽象的Builder类。ConcretBuilder 具体的Builder类。Director 同一组装过程。当然,之前实例中的Builder模式,是省略掉了Director的,这样结构更加简单。所以在很多框架源码中,涉及到Builder模式时,大多都不是经典GOF的Builder模式,而是省略后的。

  

 

  

总结

到此这篇关于Java设计模式笔记之Builder模式的文章就介绍到这了,更多相关Java设计模式Builder模式内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

 

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: