博文原址:折騰Java設計模式之建造者模式
揭陽ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!Separate the construction of a complex object from its representation, allowing the same construction process to create various representations.
將復雜對象的構造與其表現(xiàn)分離,允許相同的構造過程用來創(chuàng)建不同的表現(xiàn)。通俗點就是,一個對象創(chuàng)建過程很復雜,我們將其每項元素創(chuàng)建過程抽離出來,通過相同的構造過程可以構造出不用的對象。還不懂可以看到如下的UML圖。
此AbstractPersonBuilder
就是如上的相同的構造,而不同的表現(xiàn)就是此處的PersonOneBuilder
和PersonTwoBuilder
兩個相同方式的構造器,但是具體的實現(xiàn)是不一樣而構造出不同的表現(xiàn)。所以就是相同的構造過程而構造出不同的對象。
抽象建造者(AbstractPersonBuilder
或者Builder
):抽象類或者接口,復雜對象的屬性的抽象方法,并不涉及具體的對象部件的創(chuàng)建;
具體建造者(PersonOneBuilder
和PersonTwoBuilder
):實現(xiàn)抽象建造者,針對不同的業(yè)務,具體化復雜對象的各部分的創(chuàng)建。 在建造過程完成后,提供產(chǎn)品的實例;
指揮者(Director
):調(diào)用具體建造者來創(chuàng)建復雜對象的各個部分,在指導者中不涉及具體產(chǎn)品的信息,只負責保證對象各部分完整創(chuàng)建或按某種順序創(chuàng)建;
具體的產(chǎn)品(Person
):需創(chuàng)建的復雜對象;
源碼地址:請點擊我
在這里我分為三種情況講講建造者模式,第一種是我們最原始的建造者模式來構建,第二種是我們在實體對象時會使用的,第三種是我們平常對實體對象最常規(guī)使用方法借助lombok。
使用的真是上面按照角色來建造的方式,稍微比如下的兩種方法負責點。
抽象建造者
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類充當產(chǎn)品數(shù)據(jù)
public class Person {
private String name;
private int age;
private List 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 getChildren() {
return children;
}
public void setChildren(List 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.根據(jù)自己的風格可以定義bulid的名字,各個bulid方法的前綴以及包名,具體bulider如下代碼中。
PersonBuilder用來Person的構建者
public final class PersonBuilder {
private String name;
private int age;
private List 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 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類充當產(chǎn)品數(shù)據(jù)
public class Person {
private String name;
private int age;
private List 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 getChildren() {
return children;
}
public void setChildren(List 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 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);
}
}
結果:
第二、三種模式在我們經(jīng)常操作像對VO、DO、DTO對象時,常用如此定義。第一種標準的建造者模式,其實本身指揮者這個角色是不關心具體的產(chǎn)品實現(xiàn)的,相對于是一種解耦,對于如果新增一種建造者實現(xiàn),可以方便擴展,符合開閉原則,但是無獨有偶,實現(xiàn)了上述優(yōu)點后,但是缺點也跟著來,新增了很多類,維護成本高,如果建造者內(nèi)部發(fā)生變更,就不太適合建造者這種模式了。總體而言還是有很多使用場景的。像StringBulider其實也是一種。像之前在spring-boot的spring-cache中的擴展redis緩存的ttl和key名這篇文章中定義的RedisCacheManagerBuilder,以及我們常用的以后要講的Feign的Builder等等。
歡迎關注
另外有需要云服務器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。