《设计模式之美》(四:行为型模式)

  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. 访问模式
    将对象与操作解耦具体的操作,抽象一个操作类,然后传入具体的操作类实现

允许一个或多个操作应用在一组对象上,实现操作和对象解耦

ps:重载在大部分面向对象语言是静态绑定的,也就是说,调用类的哪个重载函数,是在编 译期间,由参数的声明类型决定的,而非运行时,根据参数的实际类型决定的
由于代码难以理解,所以一般不建议使用
public Class abstract ResourceFile{
String filePath;
public ResourceFile(String filePath){
    this.filePath = filePath
  }
abstract void accept(Visitor visitor)
}

public Class PdfFile extends ResourceFile{
  public PdfFile(String filePath) {
    super(filePath);
  }
void accept(Visitor visitor){
  visitor.visit(this)
  }
}

public Class WordFile extends ResourceFile{
  public PdfFile(String filePath) {
    super(filePath);
  }
void accept(Visitor visitor){
  visitor.visit(this)
  }
}

public Interface Visitor{
 void visit(PdfFile pdfFile);
  void visit(WordFile wordFile);
}

//读取文件
public class Extractor implements Visitor{
 void visit(PdfFile pdfFile){
  //......
  }
  void visit(WordFile wordFile){
  //......
  }
} 

//压缩文件
public class Compressor mplements Visitor{
 void visit(PdfFile pdfFile){
  //......
  }
  void visit(WordFile wordFile){
  //......
  }
} 


public static void main(String[] args){
  Extractor extractor = new Extractor();
  Compressor compressor =new Compressor();
  List<ResourceFile> files = loadFiles();
  for(ResourceFile file : files){
    file.accept(extractor)
    file.accept(compressor)
  }
}
  1. 备忘录模式
  2. 命令模式
  3. 解释器模式
  4. 中介模式
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342