●Factory是什麼:java
工廠模式同單例模式同樣,也是Java中最經常使用的設計模式之一,屬於建立型模式,它提供了一種建立對象的最佳方式。可以根據要求調用者提供的信息爲接口指定不一樣的實現類,下降耦合。設計模式
●接口及其實現類:ide
package factory; public interface Sender { public void send(); }
package factory; public class SmsSender implements Sender{ @Override public void send() { System.out.println("用短信發送..."); } }
package factory; public class EmailSender implements Sender{ @Override public void send() { System.out.println("用電子郵箱發送..."); }
●簡單工廠優化
package factory; /** * 普通工廠模式,能夠需求生產對象 * 缺點:面對複雜的初始化,會使代碼變得巨大 * 每添加一個實現類都要修改代碼,違反了里氏替換原則 * 可能會產生null對象,引起 空指針異常 * @author wqj24 * */ public class GeneraSenderFactory { public Sender produceSender(String msg) { // 根據消息,指定具體實現類 if ("email".equals(msg)) { return new EmailSender(); } if ("sms".equals(msg)) { return new SmsSender(); } // 沒有符合要求的產品 return null; } }
上代碼每寫一個一個實現類就要就要改工廠類的代碼,很不方便。能夠經過反射解決這一問題。this
●簡單工廠(反射)spa
package factory;
/**
* 簡單工廠的優化
* 優勢:使用反射,避免了添加子類就要修改工廠對象
*/ public class GeneraSenderFactory01 { public Sender produceSender(Class<? extends Sender> clazz) { Sender sender = null; try { sender = (Sender) clazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return sender; } }
在面對初始化複雜的對象時。反射的代碼會很長,且結構性差,能夠爲每一個子類都寫一個工廠方法prototype
●多個工廠方法設計
package factory; /** * 多工廠,每一個方法負責生產各自的實例 優勢能夠應對複雜的初始化 * 優勢:不會產生 null 對象 * 每一個方法負責本身對象的初始化工做,結構清晰。 */ public class ManySenderFactory { public Sender produceEmail() { return new EmailSender(); } public Sender produceSms() { return new SmsSender(); } }
也能夠將上面的方法改寫成靜態的,這樣就能夠不用new對象,直接經過類名調用工廠方法了。代理
●Singleton:指針
package com.singleton; //靜態代碼塊不必定在最開始執行,好比說 靜態代碼塊 放在 單例模式中, //但通常狀況下 靜態代碼塊是第一執行的 也就是在類加載時執行, 只執行一次 class SingletonTest { private static SingletonTest singletonTest = new SingletonTest(); static { System.out.println("======java 靜態代碼塊========"); } private SingletonTest() { System.out.println("java實現單例模式"); } public static SingletonTest getInstance() { return singletonTest; } } public class Singleton { public static void main(String[] args) { SingletonTest st = SingletonTest.getInstance(); SingletonTest st2 = SingletonTest.getInstance(); //返回true,這兩個實例是同樣的 System.out.println(st == st2); }
原型模式雖然是建立型的模式,可是與工程模式沒有關係,從名字便可看出,該模式的思想就是將一個對象做爲原型,對其進行復制、克隆,產生一個和原對象相似的新對象。本小結會經過對象的複製,進行講解。在Java中,複製對象是經過clone()實現的,先建立一個原型類:
public class Prototype implements Cloneable { public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super.clone(); return proto; } }
很簡單,一個原型類,只須要實現Cloneable接口,覆寫clone方法,此處clone方法能夠改爲任意的名稱,由於Cloneable接口是個空接口,你能夠任意定義實現類的方法名,如cloneA或者cloneB,由於此處的重點是super.clone()這句話,super.clone()調用的是Object的clone()方法,而在Object類中,clone()是native的,具體怎麼實現,我會在另外一篇文章中,關於解讀Java中本地方法的調用,此處再也不深究。在這兒,我將結合對象的淺複製和深複製來講一下,首先須要瞭解對象深、淺複製的概念:
淺複製:將一個對象複製後,基本數據類型的變量都會從新建立,而引用類型,指向的仍是原對象所指向的。
深複製:將一個對象複製後,不管是基本數據類型還有引用類型,都是從新建立的。簡單來講,就是深複製進行了徹底完全的複製,而淺複製不完全。
動態代理(運行期行爲)主要有一個 Proxy類 和一個 InvocationHandler接口
動態代理角色:
1. 抽象主題角色
2. 真實主題角色(實現了抽象主題接口)
3. 動態代理主題角色(實現了 InvocationHandler接口,並實現了 invoke()方法)
Proxy 要調用 newProxyInstance方法
代碼演示:
1.抽象主題角色 SubjectDemo.java
package com.dynamicproxy ; public interface SubjectDemo { public void request() ; }
2. 真實主題角色 RealSubjectDemo.java
package com.dynamicproxy ; public class RealSubjectDemo implements SubjectDemo { public void request() { System.out.println("實現了某請求") ; } }
3. 動態代理主題角色 DynamicProxySubjectDemo.java
package com.dynamicproxy ; import java.lang.reflect.InvocationHandler ; import java.lang.reflect.Method ; public class DynamicProxySubjectDemo implements InvocationHandler { private Object sub ; public DynamicProxySubjectDemo(Object obj) { this.sub = obj ; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before"+method) ; method.invoke(sub, args) ;//真實的調用方法操做 System.out.println("after"+method) ; return null ; } }
4.客戶端 Client.java
package com.dynamicproxy ; import java.lang.reflect.InvocationHandler ; import java.lang.reflect.Proxy ; public class Client { public static void main(String[] args) { RealSubjectDemo rsd = new RealSubjectDemo() ; InvocationHandler handler = new DynamicProxySubjectDemo(rsd) ; Class<?> classType = handler.getClass() ; // classType.getClassLoader() 動態代理類的類加載器 //rsd.getClass().getInterfaces() 代理類要實現的接口列表 //handler 指派方法調用的調用處理程序 SubjectDemo sd = (SubjectDemo)Proxy.newProxyInstance(classType.getClassLoader(), rsd.getClass().getInterfaces(), handler ) ; //這行代碼一執行 轉到 InvocationHandler handler = new DynamicProxySubjectDemo(rsd) //執行invoke方法 sd.request() ; } }