裝飾器模式
一、概念
????裝飾器模式允許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬于結構型模式,他是作為現有的類的一個包裝。
????這種模式創建了一個裝飾類,用來包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。
二、介紹
????意圖:動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾器模式相比生成子類更加靈活。
????主要解決:一般的,我們為了擴展一個類經常使用繼承方式實現,由于繼承為類引入靜態特征,并且隨著擴展功能的增多,子類會很膨脹。
????如何解決:將具體功能職責劃分,同時繼承裝飾者模式。
????關鍵代碼:Component類充當抽象角色,不應該具體實現;修飾類引用和繼承Component類,具體擴展類重寫父類方法。
????應用實例:孫悟空有72變,當它變成“廟宇”后,他的根本還是一只猴子,但是它又有了廟宇的功能。
????優點:裝飾類和被裝飾類可以獨立發展,不會相互耦合。裝飾器模式繼承的替代模式。裝飾器模式可以動態擴展一個實現類的功能
????缺點:多層裝飾比較復雜
????使用場景:擴展一個類的功能;動態增加功能,動態撤銷。
三、實現
????1、抽象組件:一個接口或抽象類,里面有想要實現的抽象方法。
public interface Shape {
?????void draw();
?}
? ??2、具體組件:實現接口,實現接口里的方法,可以多個。
public class Circle implements Shape{
?????@Override
?????public void draw() {
?????????System.out.println("Shape:circle!");
?????}
?}public class Rectangle implements Shape{
?????@Override
?????public void draw() {
?????????System.out.println("shape:rectangle!");
? ? }
?}
????3、抽象裝飾類:實現Shape接口,(一個Shape類型的變量 可有可無),實現抽象方法。這么做是為了輸出具體組建中draw方法的內容。
public class ShapeDecorator implements Shape{
?????protected Shape decoratorShape;
?????public ShapeDecorator(Shape decoratorShape) {
?????????this.decoratorShape = decoratorShape;
?????}
? ??
?????@Override
?????public void draw() {
?????????decoratorShape.draw();
?????}
}
????4、具體裝飾類:繼承抽象裝飾類ShapeDecorator,通過構造方法調用父類構造方法,實現抽象方法。 可以多個
public class RedShapeDecorator extends ShapeDecorator{
?????public RedShapeDecorator(Shape decoratorShape) {
?????????super(decoratorShape);
?????}
?????public void draw() {
?????????decoratorShape.draw();
?????????setRedBorder(decoratorShape);
?????}
?????private void setRedBorder(Shape decoratorShape) {
?????????System.out.println("Border Color:Red");
?????}
}
? ??5、測試裝飾器模式:創建對象,調用方法。 先創建具體組件對象,然后具體裝飾類對象(具體組件對象),具體裝飾類對象調用方法。
public class DecoratorPatternDemo {
?????public static void main(String[] args) {
?????????Shape circle = new Circle();
? ? ? ? ?ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
?????????ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
?????????System.out.println("Circle with normal border!");
?????????circle.draw();
?????????System.out.println("\n circle with red border!");
?????????redCircle.draw();
?????????System.out.println("\n rectangle with red border!");
?????????redRectangle.draw();
?????}
}
運行結果:
????總結:裝飾器模式在不改變原先核心功能的情況下,可以實現增強,并且不會產生很多繼承類,按照業務模塊劃分,通過不同的方法進行裝飾。
代理模式
????一個真實的對象RealSubject提供一個代理對象Proxy。通過Proxy可以調用realSubject的部分功能,并添加一些額外的業務處理,同時可以屏蔽RealSubject中未開放的接口。
????RealSubject是委托類,Proxy是代理類
????Subject是委托類和代理類的接口
????request()是委托類和代理類的共同方法
一、介紹
????一個代理類代理一個真實類的功能,替原對象進行一些操作。比如租房子的時候會去找中介,買火車票的時候找黃牛代理,但是退票改票需要本人操作。
????主要解決:直接訪問對象時帶來的問題,直接訪問會給使用者或者系統結構帶來很多麻煩,我們可以在訪問此對象時加上一個對此對象的訪問層。
????應用實例:Windows歷史快捷方式;一張支票或銀行存單是賬戶中資金的代理。支票在市場交易中用來代替現金,并提供對簽發人賬號上資金的控制;spring aop。
????優點:職責清晰;高擴展性;智能化
????缺點:由于在客戶端和真實主體之間增加了代理對象,因此有些類的代理模式可能會造成請求的處理速度變慢;;實現代理模式需要額外的工作,有些代理模式的實現非常復雜。
????使用場景:1、遠程代理。2、虛擬代理。3、Copy-on-Write代理。4、保護(Protect or Access)代理。5、Cache代理。6、防火墻處理。7、同步化代理。8、智能引用代理。
????和適配器模式的區別:適配器模式主要改變所考慮對象的接口,而代理模式不能改變所代理類的接口。
????和裝飾器模式的區別:裝飾器模式為了增加功能,而代理模式是為了加以控制。
二、實現
????代理實現分為靜態代理和動態代理。
????1、靜態代理
????????靜態代理模式其實很常見,比如買火車票,黃牛相當于是火車站的代理,我們可以通過黃牛買票,但是還能去火車站進行退票和改簽。
????接口
public interface Subject {
?????void request();
}
? ??實現接口的類
//委托類
public class RealSubject implements Subject{
?????@Override
?????public void request() {
?????????System.out.println("RealSubject");
?????}
?}//代理類
public class Proxy implements Subject{
?????private Subject subject;
?????public Proxy(Subject subject) {
?????????this.subject = subject;
?????}
?????@Override
?????public void request() {
?????????System.out.println("begin");
?????????subject.request();
?????????System.out.println("end");
?????}
}
測試:
public class ProxyTest {
?????public static void main(String[] args) {
?????????RealSubject subject = new RealSubject();
?????????Proxy proxy = new Proxy(subject);
?????????proxy.request();
?????}
}
// 結果
begin
RealSubject
end
? ??2、動態代理
????????動態代理中,代理類并不是在java代碼中實現,而是在運行時期生成,相比靜態代理,動態代理可以很方便的對委托類的方法進行統一處理,如添加方法調用次數、添加日志功能等等,動態代理分為jdk動態代理和cglib動態代理。
????????定義業務邏輯
public interface Service {
?????public abstract void add();
}
public class UserServiceImpl implements Service{
?????@Override
?????public void add() {
?????????System.out.println("this is add service");
?????}
?}
????利用java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口定義代理類的實現。
public class MyInvocationHandler implements InvocationHandler{
?????private Object target;
?????public MyInvocationHandler(Object target) {
?????????this.target = target;
?????}
?????@Override
?????public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
?????????System.out.println("------begin------");
?????????Object result = method.invoke(target,args);
?????????System.out.println("------end------");
?????????return result;
?????}
?????public Object getProxy() {
?????????ClassLoader loader = Thread.currentThread().getContextClassLoader();
?????????Class<?>[] interfaces = target.getClass().getInterfaces();?
? ? ? ? ?return Proxy.newProxyInstance(loader, interfaces, this);
?????}
}
使用動態代理
public class ProxyTest {
?????public static void main(String[] args) {
?????????Service service = new UserServiceImpl();
?????????MyInvocationHandler handler = new MyInvocationHandler(service);
?????????Service serviceProxy = (Service) handler.getProxy();
?????????serviceProxy.add();
?????}
}
執行結果:
------begin------
this is add service
------end------
三、代理對象的生成過程由Proxy類的newProxyInstance方法實現:
????1、ProxyGenerator.generateProxyClass方法負責生成代理類的字節碼,生成邏輯比較復雜。
????????????byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
????2、native方法Proxy.defineClass0()負責字節碼加載的實現,并返回對應的Class對象。
????????????Class clazz = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
????3、利用clazz.newInstance反射機制生成代理類的對象;
觀察者模式
????????MySubject類就是我們的主對象,Observer1和Observer2是依賴于MySubject的對象,當MySubject變化時,Observer1和Observer2必然變化。AbstractSubject類中定義著需要監控的對象列表,可以對其進行修改:增加或刪除被監控對象,且當MySubject變化時,負責通知在列表內存在的對象。
一、概念
????當對象間存在一對多的關系時,則使用觀察者模式。比如,當一個對象被修改時,則會自動通知依賴他的對象。觀察者模式屬于行為型模式。
????類和類之間的關系,不涉及到繼承。
二、介紹
????1、主要解決:一個對象狀態改變給其他對象通知的問題,而且要考慮到易用和低耦合,保證高度的協作。
????2、何時使用:一個對象(目標對象)的狀態發生改變,所有的依賴對象(觀察者對象)都將得到通知,進行廣播通知。
????3、關鍵代碼:在抽象類里有一個ArrayList存放觀察者們。
????4、應用實例:拍賣的時候,拍賣師觀察最高標價,然后通知給其他競價者競價。
????優點:觀察者和被觀察者是抽象耦合的;建立一套觸發機制
????缺點:如果一個被觀察者對象有很多直接或間接觀察者對象的話,將所有的觀察者都通知到會花費很多時間。
????如果在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發他們之間進行循環調用,可能導致系統崩潰。
????觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎么發生變化的,而僅僅只是知道觀察目標發生了變化。
????5、使用場景:
????????一個抽象模型有兩個方面,其中一個方面依賴于另一個方面。將這些方面封裝在獨立的對象中使它們可以各自獨立地改變和復用。
????????一個對象的改變將導致其他一個或多個對象也發生改變,而不知道具體有多少對象將發生改變,可以降低對象之間的耦合度。
????????一個對象必須通知其他對象,而并不知道這些對象是誰。
????????需要在系統中創建一個觸發鏈,A對象的行為將影響B對象,B對象的行為將影響C對象……,可以使用觀察者模式創建一種鏈式觸發機制。
? ? 6、注意事項
????????java中已經有了對觀察者模式的支持類。
????????避免循環引用
????????如果順序執行,某一觀察者錯誤會導致系統卡殼,一般采用異步方式
三、實現
????1、創建Observer類
public abstract class Observer {
?????protected Subject subject;
?????public abstract void update();
}
????2、創建Subject類
public class Subject {
?????private List<Observer> observers = new ArrayList<Observer>();
?????private int state;
?????public int getState() {
?????????return state;
?????}
?????public void setState(int state) {
?????????this.state = state;
?????????notifyAllObservers();
?????}
?????public void attach(Observer observer) {
?????????observers.add(observer);
?????}
?????public void notifyAllObservers() {
?????????for(Observer observer : observers) {
?????????????observer.update();
?????????}
?????}
}
????3、創建實體觀察者類
public class BinaryObserver extends Observer{
?????public BinaryObserver(Subject subject) {
?????????this.subject = subject;
?????????this.subject.attach(this);
?????}
?????@Override
?????public void update() {
?????????System.out.println("Binary String:" + Integer.toBinaryString(subject.getState()));
?????}
?}public class OctalObserver extends Observer{
?????public OctalObserver(Subject subject){
?????????this.subject = subject; this.subject.attach(this);
?????}
?????@Override
?????public void update() {
?????????System.out.println( "Octal String: " + Integer.toOctalString( subject.getState() ) );
?????}
?}
public class HexaObserver extends Observer{
?????public HexaObserver(Subject subject){
?????????this.subject = subject;
?????????this.subject.attach(this);
?????}
?????@Override
?????public void update() {
?????????System.out.println( "Hex String: " + Integer.toHexString( subject.getState() ).toUpperCase() );
?????}
?}
4、使用Subject和實體觀察者對象
public class ObserverPatternDemo {
?????public static void main(String[] args) {
?????????Subject subject = new Subject();
?????????new HexaObserver(subject);
?????????new OctalObserver(subject);
?????????new BinaryObserver(subject);
?????????System.out.println("First state change: 15");
?????????subject.setState(15);
?????????System.out.println("second state change: 10");
?????????subject.setState(10);
?????}
}
運行結果:
? ??觀察者模式又被稱作發布/訂閱模式,定義了對象間一對多依賴,當一個對象改變狀態時,他的所有依賴者都會收到通知并自動更新
????應用場景如下:
????????對一個對象狀態的更新,需要其他對象同步更新,而且其他對象的數量動態可變。
????????對象僅需要將自己的更新通知給其他對象而不需要知道其他對象的細節。