查看原文
其他

Java8 通用 Builder,它不香吗?

作者:cipher

来源:www.ciphermagic.cn/java8-builder.html


程序员经常会遇到灵魂拷问:你有对象吗?

没有,但我可以 new 一个!

  1. public class GirlFriend {

  2.     private String name;

  3.     private int age;

  4.     // 省略 getter & setter ...

  5.     public static void main(String[] args) {

  6.         GirlFriend myGirlFriend = new GirlFriend();

  7.         myGirlFriend.setName("小美");

  8.         myGirlFriend.setAge(18);

  9.     }

  10. }

没问题,老铁!但如果对象的属性太多,咋办?

  1. public class GirlFriend {

  2.     private String name;

  3.     private int age;

  4.     private int bust;

  5.     private int waist;

  6.     private int hips;

  7.     private List<String> hobby;

  8.     private String birthday;

  9.     private String address;

  10.     private String mobile;

  11.     private String email;

  12.     private String hairColor;

  13.     private Map<String, String> gift;

  14.     // 等等等等 ...

  15.     // 省略 getter & setter ...

  16.     public static void main(String[] args) {

  17.         GirlFriend myGirlFriend = new GirlFriend();

  18.         myGirlFriend.setName("小美");

  19.         myGirlFriend.setAge(18);

  20.         myGirlFriend.setBust(33);

  21.         myGirlFriend.setWaist(23);

  22.         myGirlFriend.setHips(33);

  23.         myGirlFriend.setBirthday("2001-10-26");

  24.         myGirlFriend.setAddress("上海浦东");

  25.         myGirlFriend.setMobile("18688888888");

  26.         myGirlFriend.setEmail("pretty-xiaomei@qq.com");

  27.         myGirlFriend.setHairColor("浅棕色带点微卷");

  28.         List<String> hobby = new ArrayList<>();

  29.         hobby.add("逛街");

  30.         hobby.add("购物");

  31.         hobby.add("买东西");

  32.         myGirlFriend.setHobby(hobby);

  33.         Map<String, String> gift = new HashMap<>();

  34.         gift.put("情人节礼物", "LBR 1912女王时代");

  35.         gift.put("生日礼物", "迪奥烈焰蓝金");

  36.         gift.put("纪念日礼物", "阿玛尼红管唇釉");

  37.         myGirlFriend.setGift(gift);

  38.         // 等等等等 ...

  39.     }

  40. }

GirlFriend 

  1. GirlFriend{name='小美'

  2. , age=18

  3. , bust=33

  4. , waist=23

  5. , hips=33

  6. , hobby=[逛街, 购物, 买东西]

  7. , birthday='2001-10-26'

  8. , address='上海浦东'

  9. , mobile='18688888888'

  10. , email='pretty-xiaomei@qq.com'

  11. , hairColor='浅棕色带点微卷'

  12. , gift={情人节礼物=LBR 1912女王时代, 生日礼物=迪奥烈焰蓝金, 纪念日礼物=阿玛尼红管唇釉}

  13. }

GirlFriend 是很美,但写起来也太麻烦了吧。

说说缺点:实例化和设置属性分开,不好维护;变量名重复写。

莫慌,看法宝~

这里不再介绍其他 Builder 实现方式,直接祭出最实用的通用Builder:

适用于所有类,不需要改造原来类,不需要 lombok 插件支持。

先看看使用姿势:

  1. public class GirlFriend {

  2.     // 省略属性 ...

  3.     // 省略 getter & setter ...


  4.     // 为了演示方便,加几个聚合方法

  5.     public void addHobby(String hobby) {

  6.         this.hobby = Optional.ofNullable(this.hobby).orElse(new ArrayList<>());

  7.         this.hobby.add(hobby);

  8.     }

  9.     public void addGift(String day, String gift) {

  10.         this.gift = Optional.ofNullable(this.gift).orElse(new HashMap<>());

  11.         this.gift.put(day, gift);

  12.     }

  13.     public void setVitalStatistics(int bust, int waist, int hips) {

  14.         this.bust = bust;

  15.         this.waist = waist;

  16.         this.hips = hips;

  17.     }

  18.     public static void main(String[] args) {

  19.         GirlFriend myGirlFriend = Builder.of(GirlFriend::new)

  20.                 .with(GirlFriend::setName, "小美")

  21.                 .with(GirlFriend::setAge, 18)

  22.                 .with(GirlFriend::setVitalStatistics, 33, 23, 33)

  23.                 .with(GirlFriend::setBirthday, "2001-10-26")

  24.                 .with(GirlFriend::setAddress, "上海浦东")

  25.                 .with(GirlFriend::setMobile, "18688888888")

  26.                 .with(GirlFriend::setEmail, "pretty-xiaomei@qq.com")

  27.                 .with(GirlFriend::setHairColor, "浅棕色带点微卷")

  28.                 .with(GirlFriend::addHobby, "逛街")

  29.                 .with(GirlFriend::addHobby, "购物")

  30.                 .with(GirlFriend::addHobby, "买东西")

  31.                 .with(GirlFriend::addGift, "情人节礼物", "LBR 1912女王时代")

  32.                 .with(GirlFriend::addGift, "生日礼物", "迪奥烈焰蓝金")

  33.                 .with(GirlFriend::addGift, "纪念日礼物", "阿玛尼红管唇釉")

  34.                 // 等等等等 ...

  35.                 .build();

  36.     }

  37. }

看到了吗!实例化和属性设置在同一条语句执行,链式操作,一路点点点,清爽!

Talk is cheap, show me the code:

  1. /**

  2.  * 通用的 Builder 模式构建器

  3.  *

  4.  * @author: CipherCui

  5.  * @since 2019/8/29

  6.  */

  7. public class Builder<T> {

  8.     private final Supplier<T> instantiator;

  9.     private List<Consumer<T>> modifiers = new ArrayList<>();

  10.     public Builder(Supplier<T> instantiator) {

  11.         this.instantiator = instantiator;

  12.     }

  13.     public static <T> Builder<T> of(Supplier<T> instantiator) {

  14.         return new Builder<>(instantiator);

  15.     }

  16.     public <P1> Builder<T> with(Consumer1<T, P1> consumer, P1 p1) {

  17.         Consumer<T> c = instance -> consumer.accept(instance, p1);

  18.         modifiers.add(c);

  19.         return this;

  20.     }

  21.     public <P1, P2> Builder<T> with(Consumer2<T, P1, P2> consumer, P1 p1, P2 p2) {

  22.         Consumer<T> c = instance -> consumer.accept(instance, p1, p2);

  23.         modifiers.add(c);

  24.         return this;

  25.     }

  26.     public <P1, P2, P3> Builder<T> with(Consumer3<T, P1, P2, P3> consumer, P1 p1, P2 p2, P3 p3) {

  27.         Consumer<T> c = instance -> consumer.accept(instance, p1, p2, p3);

  28.         modifiers.add(c);

  29.         return this;

  30.     }

  31.     public T build() {

  32.         T value = instantiator.get();

  33.         modifiers.forEach(modifier -> modifier.accept(value));

  34.         modifiers.clear();

  35.         return value;

  36.     }

  37.     /**

  38.      * 1 参数 Consumer

  39.      */

  40.     @FunctionalInterface

  41.     public interface Consumer1<T, P1> {

  42.         void accept(T t, P1 p1);

  43.     }

  44.     /**

  45.      * 2 参数 Consumer

  46.      */

  47.     @FunctionalInterface

  48.     public interface Consumer2<T, P1, P2> {

  49.         void accept(T t, P1 p1, P2 p2);

  50.     }

  51.     /**

  52.      * 3 参数 Consumer

  53.      */

  54.     @FunctionalInterface

  55.     public interface Consumer3<T, P1, P2, P3> {

  56.         void accept(T t, P1 p1, P2 p2, P3 p3);

  57.     }

  58. }

这个示例最多支持三个参数的设置属性方法,也完全够用了。如果要扩展也很容易,依葫芦画瓢,添加多个参数的Consumer。

快用你的 Builder 建个对象吧~


-End-


加小编微信:xiaobaito,免费获取一份架构师资料。还可以邀请加入咱们的「菜鸟架构」技术群一起讨论技术,禁止发广告及垃圾信息哦。


热门阅读

免费获取一份架构资料!Nginx为什么快到根本停不下来?Spring中经典的9种设计模式,要记住啊!微盟七天七夜找回删库数据
GitHub 50000+ Star 登顶,命令行的艺术!
除了负载均衡,Nginx 能做的真是太强大了!
如何搭建自己的技术架构,说得太好了!
被问懵了,什么是红黑树?

更多请关注“菜鸟架构”公众号,将不断呈现更多架构干货!



给个在看,谢谢老板!

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存