常用設計模式的實現,以及Netty中的設計模式


1.觀察者模式

  有兩個角色,觀察者和被觀察者。當被觀察者發出消息后,注冊了的觀察者會收到其消息,而沒有注冊的觀察者就不會收到。

//定義觀察者接口
interface Observer{
    //通知觀察者
    void notify(String message);
}

//定義被觀察者
interface Observed{
    //注冊觀察者
    void registerObserver(Observer o);
    //移除觀察者
    void removeObserver(Observer o);
    //通知觀察者
    void notifyObserver();
}

//實現一個被觀察者(女神)
class Gril implements Observed{
    //女神最近的消息
    private String message;
    //追求女神的人
    List<Observer> observerList;

    public Gril(){
        observerList=new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer o) {
        //多了一位追求者
        observerList.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        //一位勇士放棄了
        observerList.remove(o);
    }

    @Override
    public void notifyObserver() {
        //女神發出了一點消息
        for(Observer o:observerList){
            o.notify(message);
        }
    }

    public void setMeesage(String message){
        this.message=message;
    }
}

//實現觀察者
class Handsome_Boy implements Observer{
    @Override
    public void notify(String message) {
        System.out.println("隔壁班帥哥收到消息:"+message);
    }
}
class Lao_Wang implements Observer{
    @Override
    public void notify(String message) {
        System.out.println("老王收到消息:"+message);
    }
}
class Gay implements Observer{
    @Override
    public void notify(String message) {
        System.out.println("小伙汁收到消息:"+message);
    }
}
//測試使用
public class observer_test {
    public static void main(String[] args) {
        //首先創建幾個觀察者和被觀察者
        Gril gril=new Gril();
        Handsome_Boy boy=new Handsome_Boy();
        Gay gay=new Gay();
        Lao_Wang wang=new Lao_Wang();

        //注冊觀察者
        gril.registerObserver(boy);
        gril.registerObserver(wang);

        //被觀察者發出通知
        gril.setMeesage("我好無聊啊");
        gril.notifyObserver();
    }
}

  Netty中的應用:NioSocketChannel.writeAndFlush()。

2.責任鏈模式

  責任鏈模式,讓多個對象都有可能處理同一個請求,把多個對象連成一條鏈,讓事件在這條鏈上傳播,並且鏈上每個節點都可以終止傳播 。熟悉Netty的朋友一定了解過這種設計模式,pipeline就像一個責任鏈,ChannelHandler就是其中處理邏輯的節點。

//創建一個邏輯處理器的抽象類
abstract class AbstractHandler {
    //下一個邏輯處理器,如果你想雙向傳播,還可以定義一個前節點
    AbstractHandler nextHandler;
    //執行事件並往下傳播
    public void Execute(String message) {
        write(message);
   //可以加上其他條件,終止傳播
        if (nextHandler != null)
            nextHandler.Execute(message);
    }
    //設置下一個邏輯處理器
    public void setNextHandler(AbstractHandler handler) {
        this.nextHandler = handler;
    }
    //實際的邏輯方法,需要具體的邏輯處理器去實現
    abstract void write(String message);
}

//邏輯處理器A
class HandlerA extends AbstractHandler {
    //實際的邏輯代碼
    @Override
    void write(String message) {
        System.out.println("邏輯處理器A執行:" + message);
    }
}
//邏輯處理器B
class HandlerB extends AbstractHandler {
    @Override
    void write(String message) {
        System.out.println("邏輯處理器B執行:" + message);
    }
}
//邏輯處理器C
class HandlerC extends AbstractHandler {
    @Override
    void write(String message) {
        System.out.println("邏輯處理器C執行:" + message);
    }
}
//測試使用
public class Chain_ResponsibilityTest {
    public static void main(String[] args) {
        //首先創建邏輯處理器對象
        AbstractHandler a = new HandlerA();
        AbstractHandler b = new HandlerB();
        AbstractHandler c = new HandlerC();

        //把多個對象連成一條鏈
        a.setNextHandler(b);
        b.setNextHandler(c);

        //從頭節點開始執行
        a.Execute("你好");
    }
}

  最后ABC會按照鏈表順序輸出你好。

 

3.單例模式

  單例模式的特點是一個類全局只有一個變量,創建時是線程安全的。
  常見單例模式實現的代碼:

public class Singleton {
    private static Singleton singleton;
    private Singleton(){}
    public static Singleton getInstance(){
        if(singleton==null){
            synchronized (Singleton.class){
                if(singleton==null)
                    singleton=new Singleton();
            }
        }
        return singleton;
    }
}

  重點在於私有化構造函數,然后定義一個私有的靜態全局變量,用以存儲當前類的實例。向外提供一個獲取實例的方法,如果當前實例變量不為空,說明已經實例化過,就直接返回。否則就進行實例化,為了防止多個線程同時進入if里面重復實例化,所以得加上synchronized。
  另外,單例模式還有懶漢、餓漢之分。上面的代碼就是一個懶漢單例模式,即獲取實例時才去創建,這和Netty中的延遲加載是一個思想。而餓漢就是,定義實例變量時直接實例化了,同樣要私有化構造函數,之后獲取實例的方法直接返回這個變量就行。
  單例模式在Netty中的應用:ReadTimeoutException等。

 

4.策略模式

  簡答地說,一個類的行為或算法可以在運行時更改,這就策略模式。當一個類需要根據運行時的數據,自動去選擇執行什么邏輯,這時候我們就可以用上策略模式。下面來簡單實現一下:

//定義一個行為接口
interface Calculate{
    int operation(int num1,int num2);
}

//繼承行為接口,實現具體的行為或算法
class StrategyAdd implements Calculate{
    @Override
    public int operation(int num1,int num2) {
        return num1+num2;
    }
}
class StrategyMultiply implements Calculate{
    @Override
    public int operation(int num1, int num2) {
        return num1*num2;
    }
}
//封裝一個供外部使用的類
class Use{
    private Calculate calculate;
    //接收的參數是那個父接口,這樣實現了這個接口的類都可以傳遞進來
    public Use(Calculate calculate){
        this.calculate=calculate;
    }
    public int execute(int num1,int num2){
        //執行實際傳遞進來的類的operation方法
        return calculate.operation(num1,num2);
    }
}
public class Strategy {
    //測試使用
    public static void main(String[] args) {
        //假設這不是main方法,只是實際項目中的一個普通方法,args是用戶或其他路徑傳入的一個參數
        //根據自己的實際需求甄別參數,選擇具體行為
        if(args.length==0){
             Use use=new Use(new StrategyAdd());
             System.out.println(use.execute(5,5));//10
        }else {
            Use use1=new Use(new StrategyMultiply());
            System.out.println(use1.execute(5,5));//25
        }
    }
}

  Netty中的應用:DefaultEventExecutorChooserFactor-newChooser

 

5.裝飾者模式

  不需要修改原有類的代碼,就可以對這個類的對象附加其他效果。當要拓展一個類的功能時就可以使用這種設計模式。但這種設計模式的缺點也非常明顯,會有額外的代碼,當繼承的層級多了以后,邏輯也更復雜。

//定義一個基礎接口,獲取商品價格
interface Goods{
    float getPrice();
}

//實現一個汽車商品,獲取價格(原型)
class Car implements Goods{
    private float Price;
    public Car(float price){
        this.Price=price;
    }
    @Override
    public float getPrice() {
        return Price;
    }

}

//裝飾者的父類,集中它們的優惠效果。如何集中的,關鍵在於裝飾類獲取價格方法時調用了父類的get方法。
//可以調試捋一捋,最終的價格計算其實是在打折時才開始一層層往上計算的
class On_Sale implements Goods{
    private Goods goods;
    public On_Sale(Goods goods){
        this.goods=goods;
    }
    @Override
    public float getPrice() {
        return this.goods.getPrice();
    }
}

//汽車立減優惠(裝飾者類,原型附加功能)
class Car_Knock extends On_Sale{
    //立減金額
    private float amount;
    public Car_Knock(float amount,Goods goods){
        super(goods);
        this.amount=amount;
    }
    @Override
    public float getPrice() {
        return super.getPrice()-amount;
    }
}

//汽車打折優惠
class Car_Discount extends On_Sale{
    //打折多少
    private int discount;
    public Car_Discount(int discount,Goods goods){
        super(goods);
        this.discount=discount;
    }
    @Override
    public float getPrice() {
        return super.getPrice()*discount/10;
    }
}
//測試使用
public class decorator {
    public static void main(String[] args) {
        //創建一個原型,並傳入價格
        Goods goods=new Car(120000);
        //當立減1000后
        goods=new Car_Knock(1000,goods);
        //在立減基礎上再打個8折
        goods=new Car_Discount(8,goods);
        System.out.println(goods.getPrice());
    }
}

  Netty中的應用:WrappedByteBuf、UnreleasableByteBuf、SimpleLeakAwareByteBuf。第一個類就相當於裝飾者父類,后兩個就是裝飾類,而ByteBuf就是原型。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM