建造者模式
- 定義: 將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示
- 主要作用: 在用戶不知道對象的建造過程和細節的情況下就可以直接創建復雜的對象
- 如何使用: 用戶只需要給出指定復雜對象的類型和內容, 建造者模式負責按順序創建復雜對象(把內部的建造過程和細節隱藏起來)
- 解決的問題:
- 方便用戶創建復雜的對象 不需要知道實現過程
- 代碼復用性/封裝性 將對象構建過程和細節進行封裝/復用
- 注意事項: 與工廠模式的區別 建造者模式更加關注與零件裝配的順序, 一般用來創建更為復雜的對象
建造者一般有如下四個角色
- 產品
(Product)
: 要創建的產品類對象 - 抽象建造者
(Builder)
: 建造者的抽象類, 一般用來定義建造細節的方法, 并不涉及具體的對象部件的創建 - 具體建造者
(ConcreteBuilder)
: 具體的Builder類, 根據不同的業務邏輯, 實現對象的各個組成部分的創建 - 調度者
(Director)
: 調用具體建造者來創建復雜產品(Product)
的各個部分, 并按照一定順序或流程, 來建造復雜對象
簡單實現建造者模式
產品
(Product)
/*** @author LionLi*/
public class Product {private Long id;private String name;private String number;private Integer type;private String description;// ----- get set -----
}
建造者
(ProductBuilder)
將復雜的構建過程封裝起來, 這里如果有多種產品的建造者可以抽象出一個抽象建造者
將實現交給不同產品的具體建造者子類
/*** @author LionLi*/
public class ProductBuilder {private final Product product = new Product();public void id(Long id) {product.setId(id);}public void name(String name) {product.setName(name);}public void number(String number) {product.setNumber(number);}public void type(Integer type) {product.setType(type);}public void description(String description) {product.setDescription(description);}public Product build() {return product;}
}
測試類
/*** @author LionLi*/
public class Test {public static void main(String[] args) {ProductBuilder builder = new ProductBuilder();builder.id(1L);builder.name("666");builder.number("CP123");builder.type(1);builder.description("測試");System.out.println(builder.build());}
}
鏈式建造者寫法
在平常的應用中, 建造者模式通常是采用鏈式編程的方式構建對象, 修改
ProductBuilder
代碼
/*** 鏈式建造者** @author LionLi*/
public class ProductBuilder {private final Product product = new Product();public ProductBuilder id(Long id) {product.setId(id);return this;}public ProductBuilder name(String name) {product.setName(name);return this;}public ProductBuilder number(String number) {product.setNumber(number);return this;}public ProductBuilder type(Integer type) {product.setType(type);return this;}public ProductBuilder description(String description) {product.setDescription(description);return this;}public Product build() {return product;}
}
測試類
/*** @author LionLi*/
public class Test {public static void main(String[] args) {ProductBuilder builder = new ProductBuilder();Product product = builder.id(1L).name("666").number("CP123").type(1).description("測試鏈式").build();System.out.println(product);}
}
Lombok @Builder
注解實現建造者模式
我們項目中最常使用的 Lombok 工具是如何實現的建造者呢, 我們來看一下
改造產品類適用
@Builder
注解, 只需要增加一個注解即可完成建造者模式是不是非常的簡單
/*** @author LionLi*/
@Data
@Builder
public class Product {private Long id;private String name;private String number;private Integer type;private String description;
}
測試類
/*** @author LionLi*/
public class Test {public static void main(String[] args) {Product.ProductBuilder builder = Product.builder();Product product = builder.id(1L).name("666").number("CP123").type(1).description("測試鏈式").build();System.out.println(product);}
}
我們來看一下 Lombok 是如何實現的建造者模式
進入代碼目錄下的target
目錄找到class下的編譯后的Product
類
首先是
Product
本身
然后是建造者
ProductBuilder
可以看出跟我們上面寫的幾乎是相同的
Spring中建造者模式的應用
Spring框架中的建造者模式的應用有很多, 例如
BeanDefinitionBuilder
用于構建Bean定義信息對象, 將BeanDefinition
的創建過程進行封裝, 并提供BeanDefinitionBuilder
各種Bean定義信息對象的創建方法, 其實現更加的簡潔并且符合實際開發需求.
大家可以搜索找到 BeanDefinitionBuilder
類查看實現
BeanDefinitionBuilder
代碼, 可以看出bean的構建過程還是很復雜的每個方法都做了很多操作
/*** Programmatic means of constructing* {@link org.springframework.beans.factory.config.BeanDefinition BeanDefinitions}* using the builder pattern. Intended primarily for use when implementing Spring 2.0* {@link org.springframework.beans.factory.xml.NamespaceHandler NamespaceHandlers}.** @author Rod Johnson* @author Rob Harrop* @author Juergen Hoeller* @since 2.0*/
public final class BeanDefinitionBuilder {/*** Create a new {@code BeanDefinitionBuilder} used to construct a {@link GenericBeanDefinition}.*/public static BeanDefinitionBuilder genericBeanDefinition() {return new BeanDefinitionBuilder(new GenericBeanDefinition());}/*** Create a new {@code BeanDefinitionBuilder} used to construct a {@link GenericBeanDefinition}.* @param beanClassName the class name for the bean that the definition is being created for*/public static BeanDefinitionBuilder genericBeanDefinition(String beanClassName) {BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());builder.beanDefinition.setBeanClassName(beanClassName);return builder;}// ----- 太多了省略部分代碼 -----/*** The {@code BeanDefinition} instance we are creating.*/private final AbstractBeanDefinition beanDefinition;/*** Our current position with respect to constructor args.*/private int constructorArgIndex;/*** Enforce the use of factory methods.*/private BeanDefinitionBuilder(AbstractBeanDefinition beanDefinition) {this.beanDefinition = beanDefinition;}/*** Return the current BeanDefinition object in its raw (unvalidated) form.* @see #getBeanDefinition()*/public AbstractBeanDefinition getRawBeanDefinition() {return this.beanDefinition;}/*** Validate and return the created BeanDefinition object.*/public AbstractBeanDefinition getBeanDefinition() {this.beanDefinition.validate();return this.beanDefinition;}/*** Set the name of a static factory method to use for this definition,* to be called on this bean's class.*/public BeanDefinitionBuilder setFactoryMethod(String factoryMethod) {this.beanDefinition.setFactoryMethodName(factoryMethod);return this;}/*** Add an indexed constructor arg value. The current index is tracked internally* and all additions are at the present point.*/public BeanDefinitionBuilder addConstructorArgValue(@Nullable Object value) {this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(this.constructorArgIndex++, value);return this;}/*** Add a reference to a named bean as a constructor arg.* @see #addConstructorArgValue(Object)*/public BeanDefinitionBuilder addConstructorArgReference(String beanName) {this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(this.constructorArgIndex++, new RuntimeBeanReference(beanName));return this;}// ----- 太多了省略部分代碼 -----/*** Append the specified bean name to the list of beans that this definition* depends on.*/public BeanDefinitionBuilder addDependsOn(String beanName) {if (this.beanDefinition.getDependsOn() == null) {this.beanDefinition.setDependsOn(beanName);}else {String[] added = ObjectUtils.addObjectToArray(this.beanDefinition.getDependsOn(), beanName);this.beanDefinition.setDependsOn(added);}return this;}/*** Set whether this bean is a primary autowire candidate.* @since 5.1.11*/public BeanDefinitionBuilder setPrimary(boolean primary) {this.beanDefinition.setPrimary(primary);return this;}/*** Apply the given customizers to the underlying bean definition.* @since 5.0*/public BeanDefinitionBuilder applyCustomizers(BeanDefinitionCustomizer... customizers) {for (BeanDefinitionCustomizer customizer : customizers) {customizer.customize(this.beanDefinition);}return this;}}
BeanDefinitionBuilder
的應用
大家可以搜索找到 AbstractSingleBeanDefinitionParser
類查看實現
AbstractSingleBeanDefinitionParser
是一個解析并生成單例Bean對象的解析器, BeanDefinitionBuilder
具體如何創建Bean實例的可以查看這個類的實現