博文原址:折騰Java設計模式之建造者模式java
Separate the construction of a complex object from its representation, allowing the same construction process to create various representations.git
將複雜對象的構造與其表現分離,容許相同的構造過程用來建立不一樣的表現。通俗點就是,一個對象建立過程很複雜,咱們將其每項元素建立過程抽離出來,經過相同的構造過程能夠構造出不用的對象。還不懂能夠看到以下的UML圖。github
此AbstractPersonBuilder
就是如上的相同的構造,而不一樣的表現就是此處的PersonOneBuilder
和PersonTwoBuilder
兩個相同方式的構造器,可是具體的實現是不同而構造出不一樣的表現。因此就是相同的構造過程而構造出不一樣的對象。redis
抽象建造者(AbstractPersonBuilder
或者Builder
):抽象類或者接口,複雜對象的屬性的抽象方法,並不涉及具體的對象部件的建立;spring
具體建造者(PersonOneBuilder
和PersonTwoBuilder
):實現抽象建造者,針對不一樣的業務,具體化複雜對象的各部分的建立。 在建造過程完成後,提供產品的實例;設計模式
指揮者(Director
):調用具體建造者來建立複雜對象的各個部分,在指導者中不涉及具體產品的信息,只負責保證對象各部分完整建立或按某種順序建立;緩存
具體的產品(Person
):需建立的複雜對象;微信
源碼地址:請點擊我ide
在這裏我分爲三種狀況講講建造者模式,第一種是咱們最原始的建造者模式來構建,第二種是咱們在實體對象時會使用的,第三種是咱們日常對實體對象最常規使用方法藉助lombok。spring-boot
使用的真是上面按照角色來建造的方式,稍微好比下的兩種方法負責點。
抽象建造者
public abstract class AbstractPersonBuilder { protected Person product = new Person(); public abstract void buildName(); public abstract void buildAge(); public abstract void buildChildren(); public Person build() { return product; } }
第一個具體建造者
public class PersonOneBuilder extends AbstractPersonBuilder { public void buildName() { product.setName("老one"); } public void buildAge() { product.setAge(44); } public void buildChildren() { product.setChildren(Lists.newArrayList("小one")); } }
第二個具體建造者
public class PersonTwoBuilder extends AbstractPersonBuilder { public void buildName() { product.setName("老two"); } public void buildAge() { product.setAge(55); } public void buildChildren() { product.setChildren(Lists.newArrayList("小two")); } }
Person類充當產品數據
public class Person { private String name; private int age; private List<String> children; @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", children=" + children + '}'; } 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 List<String> getChildren() { return children; } public void setChildren(List<String> children) { this.children = children; } }
指揮者,指定具體的建造者用來建造對象
public class Director { private AbstractPersonBuilder builder; public Director(AbstractPersonBuilder builder) { this.builder = builder; } public void setBuilder(AbstractPersonBuilder builder) { this.builder = builder; } public Person construct() { builder.buildName(); builder.buildAge(); builder.buildChildren(); return builder.build(); } }
示例
@Slf4j public class Application { public static void main(String[] args) { Director director = new Director(new PersonOneBuilder()); Person person = director.construct(); log.info("person的信息:{}", person); director.setBuilder(new PersonTwoBuilder()); person = director.construct(); log.info("person的信息:{}", person); } }
結果:
第二種方式比上面那種簡單些,由於咱們只指定了一種構造方式,而且還能夠借用第三方工具IDEA+Plugins。
在IDEA中能夠搜索
使用方法:
1.找到對應須要添加bulid的類經過自動生成快捷鍵能夠查看到build
2.根據本身的風格能夠定義bulid的名字,各個bulid方法的前綴以及包名,具體bulider以下代碼中。
PersonBuilder用來Person的構建者
public final class PersonBuilder { private String name; private int age; private List<String> children; private PersonBuilder() { } public static PersonBuilder builder() { return new PersonBuilder(); } public PersonBuilder withName(String name) { this.name = name; return this; } public PersonBuilder withAge(int age) { this.age = age; return this; } public PersonBuilder withChildren(List<String> children) { this.children = children; return this; } public Person build() { Person person = new Person(); person.setName(name); person.setAge(age); person.setChildren(children); return person; } }
Person類充當產品數據
public class Person { private String name; private int age; private List<String> children; @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", children=" + children + '}'; } 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 List<String> getChildren() { return children; } public void setChildren(List<String> children) { this.children = children; } }
示例
@Slf4j public class Application { public static void main(String[] args) { Person wang = PersonBuilder.builder() .withAge(40) .withName("老王") .withChildren(Lists.newArrayList("李一一", "吳老三")) .build(); log.info("老王的信息:{}", wang); } }
結果以下:
第三種模式相對來講就簡單很是多,由於咱們借用的是lombok的@Builder註解。lombok在18.2版本中引入了@SuperBulider註解用來解決@Builder類的繼承不生效的問題。詳細的使用闊以看我上篇文章 折騰Java設計模式之模板方法模式
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Person { private String name; private int age; private List<String> children; }
@Slf4j public class Application { public static void main(String[] args) { Person wang = Person.builder() .age(40) .name("老王") .children(Lists.newArrayList("李一一", "吳老三")) .build(); log.info("老王的信息:{}", wang); } }
結果:
第2、三種模式在咱們常常操做像對VO、DO、DTO對象時,經常使用如此定義。第一種標準的建造者模式,其實自己指揮者這個角色是不關心具體的產品實現的,相對因而一種解耦,對於若是新增一種建造者實現,能夠方便擴展,符合開閉原則,可是無獨有偶,實現了上述優勢後,可是缺點也跟着來,新增了不少類,維護成本高,若是建造者內部發生變動,就不太適合建造者這種模式了。整體而言仍是有不少使用場景的。像StringBulider其實也是一種。像以前在spring-boot的spring-cache中的擴展redis緩存的ttl和key名這篇文章中定義的RedisCacheManagerBuilder,以及咱們經常使用的之後要講的Feign的Builder等等。
歡迎關注