漫畫:什么是 “建造者模式” ?
時間:2021-09-28 16:33:28
手機看文章
掃描二維碼
隨時隨地手機看文章
[導讀]—————?第二天?—————————————————?首先,我們來定義一個Product類:public?class?Product?{????ArrayList?parts?=?new?ArrayList();????public?void?add(String?part)?{????????parts.add(part);????}????public?void?show()?{????????System.out.println(parts);????}}?接下來,我們定義抽象的Builder類:public?abstract?class?Builder?{????public?abs...
—————? 第二天? —————
————————————
?
首先,我們來定義一個Product類:
public?class?Product?{
????ArrayList?parts?=?new?ArrayList();
????public?void?add(String?part)?{
????????parts.add(part);
????}
????public?void?show()?{
????????System.out.println(parts);
????}
}
?接下來,我們定義抽象的Builder類:
public?abstract?class?Builder?{
????public?abstract?void?buildPartA();
????public?abstract?void?buildPartB();
????public?abstract?Product?getResult()?;
}
然后,是具體的Builder實現類:
public?class?ConcreteBuilder?extends?Builder?{
????private?Product?product?=?new?Product();
????public?Product?getResult()?{
????????return?product;
????}
????@Override
????public?void?buildPartA()?{
????????product.add("構建產品的上半部分");
????}
????@Override
????public?void?buildPartB()?{
????????product.add("構建產品的下半部分");
????}
}
在Builder類之外,則是Director類來控制Builder的生產過程:
public?class?Director?{
????private?Builder?builder;
????public?Director(Builder?builder)?{
????????this.builder?=?builder;
????}
????public?void?construct()?{
????????builder.buildPartA();
????????builder.buildPartB();
????}
}
最后,是客戶端的測試代碼:
Builder?builder?=?new?ConcreteBuilder();
Director?director?=?new?Director(builder);
director.construct();
Product?product?=?builder.getResult();
product.show();
我們來看一下運行的結果:
[構建產品的上半部分,?構建產品的下半部分]
//?默認采用Builder進行建造
public?OkHttpClient()?{
??this(new?Builder());
}
//?由builder配置分發(fā)器、代理、協(xié)議以及自定義攔截器等
OkHttpClient(Builder?builder)?{
??this.dispatcher?=?builder.dispatcher;
??this.proxy?=?builder.proxy;
??this.protocols?=?builder.protocols;
??/**?省略大段代碼?*/
??boolean?isTLS?=?false;
??for?(ConnectionSpec?spec?:?connectionSpecs)?{
????isTLS?=?isTLS?||?spec.isTls();
??}
??/**?省略大段代碼.?*/
??if?(interceptors.contains(null))?{
????throw?new?IllegalStateException("Null?interceptor:?"? ?interceptors);
??}
??if?(networkInterceptors.contains(null))?{
????throw?new?IllegalStateException("Null?network?interceptor:?"? ?networkInterceptors);
??}
}
public?static?final?class?Builder?{
??public?Builder()?{
//?分發(fā)器、協(xié)議、代理的默認參數
????dispatcher?=?new?Dispatcher();
????protocols?=?DEFAULT_PROTOCOLS;
????proxySelector?=?ProxySelector.getDefault();
????if?(proxySelector?==?null)?{
??????proxySelector?=?new?NullProxySelector();
????}
??}
??Builder(OkHttpClient?okHttpClient)?{
????//?反向配置分發(fā)器、代理、協(xié)議
????this.dispatcher?=?okHttpClient.dispatcher;?
????this.proxy?=?okHttpClient.proxy;?
????this.protocols?=?okHttpClient.protocols;
//?新增所有自定義攔截器和自定義網絡攔截器
????this.interceptors.addAll(okHttpClient.interceptors);
????this.networkInterceptors.addAll(okHttpClient.networkInterceptors);
??}
??//?配置代理
??public?Builder?proxy(@Nullable?Proxy?proxy)?{
????this.proxy?=?proxy;
????return?this;
??}
??//?向攔截器鏈中增加自定義攔截器
??public?Builder?addInterceptor(Interceptor?interceptor)?{
????if?(interceptor?==?null)?throw?new?IllegalArgumentException("interceptor?==?null");
????interceptors.add(interceptor);
????return?this;
??}
??//?最后是build()方法,生成OkHttpClient對象
??public?OkHttpClient?build()?{
????return?new?OkHttpClient(this);
??}
}
/**將指定的字符串追加到此字符序列*/
@Override
public?StringBuilder?append(CharSequence?s)?{
????super.append(s);//?實現過程略
????return?this;
}
/**將此字符序列用其反轉形式取代*/
@Override
public?StringBuilder?reverse()?{
????super.reverse();//?實現過程略
????return?this;
}
下面讓我們來編寫一下測試代碼:StringBuilder?sb?=?new?StringBuilder("若為自由故");
sb.append("只要主義真");
sb.reverse();
System.out.println(sb);
StringBuilder?sb1?=?new?StringBuilder("若為自由故");
sb1.reverse();
sb1.append("只要主義真");
System.out.println(sb1);
測試結果如下:
System.out:?真義主要只故由自為若
System.out:?故由自為若只要主義真
建造者模式與簡單工程模式的區(qū)別,在于建造者模式多出一個Builder類,使得創(chuàng)建對象的靈活性大大增加,適用于如下場景:
(1)創(chuàng)建一個對象,多個同樣的方法的調用順序不同,產生的結果不同(2)創(chuàng)建一個對象,特別復雜,參數多,而且很多參數都有默認值?
System.out.println("Hello?World");
短短一行代碼,背后有什么樣的機制呢?
Java的編譯原理,是將Hello.java編譯成能被VM理解的Hello.class,然后再轉化為能被不同硬件設備理解的bytecode進而執(zhí)行的。
著名的字節(jié)碼增強框架ASM,就是在Hello.java編譯成Hello.class時可以讀取并分析類信息、改變類行為、增強類功能甚至生成新的類的bytecode分析和操作框架。
我們來看一下相關的代碼,代碼當中的mv,來自ASM框架的MethodVisitor接口。
//?訪問System類的類型為PrintSystem類型的靜態(tài)變量out
mv.visitFieldInsn(Opcodes.GETSTATIC,?"java/lang/System",?"out",?"Ljava/io/PrintStream;");
//?訪問常量池中的數據"Hello?World"
mv.visitLdcInsn("Hello?World");
//?調用PrintStream類的println()方法并把剛才獲取到的對象當做String類型的參數傳入
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,?"java/io/PrintStream",?"println",?"(Ljava/lang/String;)V",?false);