《設計模式之美》(四:行爲型模式)

  1. 觀察者模式
關鍵詞 
Subject-Observer
Publisher-Subscriber
Producer-Consumer
EventEmitter-EventListener
Dispatcher-Listener
同步阻塞(一般默認),異步非阻塞,進程內,跨進程
如果要實現異步非阻塞就讓notifyObserver在線程裏面執行
public class Message {
    private String msg;

    public Message(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }

    
}


public interface Observer {
    void onResult(Message message);
}

public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(Message message);
}

public class ConcreteSubject implements Subject{
    private List<Observer> observers = new ArrayList<>();

    public void registerObserver(Observer observer){
        observers.add(observer);
    }

    public void removeObserver(Observer observer){
        observers.remove(observer);
    }

    public void notifyObservers(Message message){
        for (Observer observer: observers) {
            observer.onResult(message);
        }
    }
}


public class ConcernObserver1 implements Observer {
    @Override
    public void onResult(Message message) {
        System.out.println("i am ConcernObserver1 "+message.getMsg());
    }
}

public class ConcernObserver2 implements Observer {
    @Override
    public void onResult(Message message) {
        System.out.println("i am ConcernObserver2 "+message.getMsg());
    }
}

  public static void main(String[] args){
        ConcreteSubject concreteSubject = new ConcreteSubject();
        concreteSubject.registerObserver(new ConcernObserver1());
        concreteSubject.registerObserver(new ConcernObserver2());
        concreteSubject.notifyObservers(new Message("haha")); 
    }

手動實現一個EventBus
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Bean
public @interface Subscriber {

}

public class ObserverAction {
    private Object target;
    private Method method;

    public ObserverAction(Object target, Method method) {
        this.target = target;
        this.method = method;
    }

    public void executed(Object event){
        try {
            method.invoke(target,event);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

public class ObserverRegistry {
    //CopyOnWriteArraySet 寫的時候,有個備份 不影響讀; 多線程加鎖限制
    private ConcurrentMap<Class<?>, CopyOnWriteArraySet<ObserverAction>> registry = new ConcurrentHashMap<>();

    public void register(Object observer){
        Map<Class<?>, Collection<ObserverAction>> observerActions = findAllObserverAction(observer);
        for(Map.Entry<Class<?>,Collection<ObserverAction>> entry : observerActions.entrySet()){
            Class<?> eventType = entry.getKey();
            Collection<ObserverAction> eventActions = entry.getValue();
            CopyOnWriteArraySet<ObserverAction> registerEventActions = registry.get(eventType);
            if (registerEventActions == null){
                registry.putIfAbsent(eventType,new CopyOnWriteArraySet<>());
                registerEventActions = registry.get(eventType);
            }
            registerEventActions.addAll(eventActions);
        }
    }


    public List<ObserverAction> getMatchedObserverActions(Object event){
        List<ObserverAction> matchedActionList = new ArrayList<>();
        Class<?> postedEventType = event.getClass();
        for (Map.Entry<Class<?>, CopyOnWriteArraySet<ObserverAction>> entry : registry.entrySet()){
            Class<?> eventType = entry.getKey();
            CopyOnWriteArraySet<ObserverAction> eventActions = entry.getValue();
            if (postedEventType.isAssignableFrom(eventType)){
                matchedActionList.addAll(eventActions);
            }
        }
        return matchedActionList;

    }

    private Map<Class<?>, Collection<ObserverAction>> findAllObserverAction(Object observer){
        Map<Class<?>,Collection<ObserverAction>> observerActions = new HashMap<>();
        Class<?> clazz = observer.getClass();
        for (Method method : getAnnotatedMethods(clazz)){
            Class<?>[] parameterTypes = method.getParameterTypes();
            Class<?> eventType = parameterTypes[0];
            if (!observerActions.containsKey(eventType)){
                observerActions.put(eventType,new ArrayList<>());
            }
            observerActions.get(eventType).add(new ObserverAction(observer,method));
        }
        return observerActions;
    }

    private List<Method> getAnnotatedMethods(Class<?> clazz){
        List<Method> annotatedMethod = new ArrayList<>();
        for (Method method : clazz.getDeclaredMethods()){
            if (method.isAnnotationPresent(Subscriber.class)){
                Class<?>[] parameterTypes = method.getParameterTypes();
                Preconditions.checkArgument(parameterTypes.length == 1,"Method %s has @Subscribe annotation but has %s parameters." + "Subscriber methods must have exactly 1 parameter.",
                        method, parameterTypes.length);
                annotatedMethod.add(method);
            }
        }
        return annotatedMethod;
    }

}

public class EventBus {
    private ObserverRegistry observerRegistry = new ObserverRegistry();
    private Executor executor;

    public EventBus() {
        this(MoreExecutors.directExecutor());
    }

    public EventBus(Executor executor) {
        this.executor = executor;
    }

    public void register(Object object){
        observerRegistry.register(object);
    }

    public void post(Object event){
        List<ObserverAction> matchedObserverActions = observerRegistry.getMatchedObserverActions(event);
        for (ObserverAction observerAction: matchedObserverActions) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    observerAction.executed(event);
                }
            });
        }
    }
}
  1. 模板模式
    • 定義:定義了方法的骨架,將某些步驟延遲到子類實現
    • 作用:複用和擴展
    • 模板和Callback:模板是繼承,Callback是組合
public abstract class BaseTemplate {

    final void doTask(){
        before();
        System.out.println("BaseTemplate Task");
        after();
    }

    protected abstract void before();

    protected abstract void after();
}


public class ConcernTemplate extends BaseTemplate {
    @Override
    protected void before() {
     System.out.println("i am ConcernTemplate before");
    }

    @Override
    protected void after() {
        System.out.println("i am ConcernTemplate after");
    }
}

public interface ILoginService {
    void login(String userName,String pwd);
}

public class UserService {
    private ILoginService loginService;

    public void addLoginService(ILoginService loginService){
        this.loginService = loginService;
    }

    public void login(String userName,String pwd){
        if (loginService != null){
            loginService.login(userName,pwd);
        }else {
            throw new ExceptionInInitializerError("should call addLoginService before");
        }
    }

}

public static void main(String[] args){
        BaseTemplate template = new ConcernTemplate();
        template.doTask();

        UserService userService = new UserService();
        userService.addLoginService(new ILoginService() {
            @Override
            public void login(String userName, String pwd) {
                if ("tml".equals(userName) & "123".equals(pwd)){
                    System.out.println("login Success");
                }else {
                    System.out.println("login fail");
                }
            }
        });
        userService.login("tml","123");
    }
  1. 策略模式
    • 策略模式通常和工廠方法一起使用,策略模式重點在於靈活選擇,工廠方法在於創建實例
    • 實現:緩存本地, if else(一個是代碼寫死,一個是配置文件,讀取,動態);通過關係表,避免if else
public interface Strategy {
    void algorithmInterface();
}


public class ConcernStrategyA implements Strategy {
    @Override
    public void algorithmInterface() {
        System.out.println("ConcernStrategyA");
    }
}

public class ConcernStrategyB implements Strategy {
    @Override
    public void algorithmInterface() {
        System.out.println("ConcernStrategyB");
    }
}

public class ConcernStrategyC implements Strategy {
    @Override
    public void algorithmInterface() {
        System.out.println("ConcernStrategyB");
    }
}

//緩存  查表法 避免if else
public class StrategyFactory {
    private static Map<String,Strategy> strategies = new HashMap<>();

    static {
        strategies.put("A",new ConcernStrategyA());
        strategies.put("B",new ConcernStrategyA());
        strategies.put("C",new ConcernStrategyA());
    }

    public static Strategy getStrategy(String type){
        if (type == null || type.isEmpty()){
            throw new IllegalArgumentException("type should not be empty");
        }else {
            return strategies.get(type);
        }
    }
}

// if else
public class StrategyFactory1 {
    public static Strategy getStrategy(String type){
        if (type == null || type.isEmpty()){
            throw new IllegalArgumentException("type should not be empty");
        }else {
            if ("A".equals(type)){
                return new ConcernStrategyA();
            }else if("B".equals(type)){
                return new ConcernStrategyB();
            }else if ("C".equals(type)){
                return new ConcernStrategyC();
            }else {
                return null;
            }
        }
    }
}

  public static void main(String[] args) throws Exception {
        Properties properties = new Properties();
        properties.load(new FileInputStream("./config.properties"));
        String strategyType = (String) properties.get("strategy");
        Strategy strategy = StrategyFactory.getStrategy(strategyType);
        strategy.algorithmInterface();

        Strategy strategy1 = StrategyFactory1.getStrategy("A");
        strategy1.algorithmInterface();
    }

//config.properties
strategy:A

  1. 責任鏈模式
    • 應用:常用來開發過濾器和攔截器
    • 實例:Servlet Filter、Spring Interceptor
Filter & Interceptor & AOP 相同點與不同點
Filter依賴Servlet,作用於RSET api
Interceptor 依賴Spring Framework基於反射,作用於REST api
AOP 動態代理,作用於Bean
public abstract class Handler {
    Handler successor;

    public Handler() {
    }

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public  void handle(){
        boolean handle = doHandle();
        if (!handle && successor != null){
            successor.handle();
        }
    };
    public abstract boolean doHandle();
}

public class HandlerA extends Handler {
    @Override
    public boolean doHandle() {
        System.out.println("AAA");
        return false;

    }
}

public class HandlerB extends Handler {
    @Override
    public boolean doHandle() {
        System.out.println("BBB");
        return false;
    }
}

public class HandleChain {
    private Handler head  = null;
    private Handler tail = null;

    public void addHandle(Handler handler){
        handler.setSuccessor(null);
        if (head == null){
            head = handler;
            tail = handler;
            return;
        }
        tail.setSuccessor(handler);
        tail = handler;
    }

    public void handle(){
        if (head != null){
            head.handle();
        }
    }
}

 public static void main(String[] args){
        HandleChain chain = new HandleChain();
        chain.addHandle(new HandlerA());
        chain.addHandle(new HandlerB());
        chain.handle();
        //還有一種直接在HandleChain存儲一個列表或者數組 循環調用
    }
  1. 狀態模式
    • 分支邏輯:if else 適合狀態比較少
    • 查表法:二維數組,狀態轉移比較簡單
    • 狀態模式:相互耦合,適合事件觸發比較複雜
public enum State {//狀態
    Small(0),Super(1),Cape(2),Fire(3);

    private int state;
    State(int state) {
        this.state = state;
    }

    public int getState() {
        return state;
    }
}

public interface StateMachine {
    void obtainMushRoom();
    void obtainCap();
    void obtainFireFlower();
    void meetMonster();

}

// 方式一if else
public class MarioStateMachine implements StateMachine{
    State state = State.Small;
    int score;
    public void obtainMushRoom(){
        state = State.Super;
        score +=100;
    }

    public void obtainCap(){
        if (state == State.Small){
            state = State.Cape;
            score +=200;
        }else if(state == State.Super){
            state = State.Cape;
            score +=200;
        }
    }

    public void obtainFireFlower(){//事件
        if (state == State.Small){
            state = State.Fire;
            score +=300;
        }else if(state == State.Super){
            state = State.Fire;
            score +=300;
        }
    }

    public void meetMonster(){
        if (state == State.Super){
            state = State.Small;
            score -=100;
        }else if(state == State.Cape){
            state = State.Small;
            score -=200;
        }else if (state == State.Fire){
            state = State.Small;
            score -=300;
        }
    }
} 

public enum  Event {
    GOT_MushRoom(0),GOT_Cap(1),GOT_FireFlower(2),MEET_Monster(3);
    private int event;
    Event(int event) {
        this.event = event;
    }

    public int getEvent() {
        return event;
    }
}

//方式二 查表法
public class MarioStateMachine1 implements StateMachine{
    private int score;
    private State currentState;
   private static final  State[][] transitionTable = {{State.Super,State.Cape,State.Fire,State.Small},
            {State.Super,State.Cape,State.Fire,State.Small},
            {State.Cape,State.Cape,State.Cape,State.Small},
            {State.Fire,State.Fire,State.Fire,State.Small}};

    private static final int[][] actionTable = {{+100,+200,+300,+0},
            {+0,+300,+200,-100},
            {+0,+0,+0,-200},
            {+0,+0,+0,-300}};

    @Override
    public void obtainMushRoom() {
        executeEvent(Event.GOT_MushRoom);
    }

    @Override
    public void obtainCap() {
        executeEvent(Event.GOT_Cap);
    }

    @Override
    public void obtainFireFlower() {
        executeEvent(Event.GOT_FireFlower);
    }

    @Override
    public void meetMonster() {
        executeEvent(Event.MEET_Monster);
    }

    public void executeEvent(Event event){
        int event1 = event.getEvent();
        int state = currentState.getState();
        this.currentState = transitionTable[event1][state];
        this.score = score + actionTable[event1][state];
    }

}

public interface IMario {
    State getName();
    void obtainMushRoom();
    void obtainCap();
    void obtainFireFlower();
    void meetMonster();
}

//CapMario 等代碼相似,省略
public class SmallMario implements IMario {
    private MarioStateMachine2 marioStateMachine;

    public SmallMario(MarioStateMachine2 marioStateMachine) {
        this.marioStateMachine = marioStateMachine;
    }

    @Override
    public State getName() {
        return State.Small;
    }

    @Override
    public void obtainMushRoom() {
        marioStateMachine.setMario(new SmallMario(marioStateMachine));
        marioStateMachine.setScore(marioStateMachine.getScore() + 100);
    }

    @Override
    public void obtainCap() {

    }

    @Override
    public void obtainFireFlower() {

    }

    @Override
    public void meetMonster() {

    }
}


//方式三 狀態模式
public class MarioStateMachine2 {
    //省略一些代碼
    private int score;
    private IMario mario;

    public int getScore() {
        return score;
    }

    public IMario getMario() {
        return mario;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public void setMario(IMario mario) {
        this.mario = mario;
    }
}
  1. 迭代器模式
    • ArrayIterator ArrayList 兩者組合
比較:for 、foreach(語法糖,底層是Iterator)、Iterator 
對於數組列表三者方式都可以,但是對於複雜的數據結構,比如圖,樹,就不太方便
迭代器,增刪元素有時候會導致出現異常,比較常用的處理方式是增刪操作報錯
迭代器有remove方法,遍歷結合的時候可以安全的刪除
可以採用爲集合生產快照的方式來避免增刪出錯
  1. 訪問模式
  2. 備忘錄模式
  3. 命令模式
  4. 解釋器模式
  5. 中介模式
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章