高性能高质量代码:观察者模式

127 阅读3分钟

书写代码必须符合高质量高性能要求,这也是能够在视觉上和其他程序员拉开差距的技能,同时也是一个优秀程序员的基本要求。

何为高质量: 代码具备可维护性,可读性,可扩展性,灵活性,简洁性,可复用性, 可测试性。

何为高性能: 代码能尽可能的提高处理效率。

如何写高质量高性能代码: 首先要做的就是精通设计模式,设计原则,掌握各种算法以及了解硬件底层相关内容。

今天我们来说一说观察者模式。

1观察者模式

在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。

//定义被观察者接口
public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(Message message);
}
//定义观察者接口
public interface Observer {
    void update(Message message);
}

//实现被观察者
public class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<Observer>();
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    @Override
    public void notifyObservers(Message message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

//实现观察者1
public class ConcreteObserverOne implements Observer {
    @Override
    public void update(Message message) {
        //TODO: 获取消息通知,执行自己的逻辑...
        System.out.println("ConcreteObserverOne is notified.");
    }
}
//实现观察者2
public class ConcreteObserverTwo implements Observer {
    @Override
    public void update(Message message) {
        //TODO: 获取消息通知,执行自己的逻辑...
        System.out.println("ConcreteObserverTwo is notified.");
    }
}

//模拟代码运行demo
public class Demo {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        subject.registerObserver(new ConcreteObserverOne());
        subject.registerObserver(new ConcreteObserverTwo());
        subject.notifyObservers(new Message());
    }
}

设计模式最大的一个好处就是解耦,观察者模式就是将观察者和被观察者代码解耦。

观察者模式有同步阻塞的实现方式,也有异步非阻塞的实现方式; 同步方式比较简单,对于异步非阻塞观察者模式,如果只是实现一个简易版本,不考虑任何通用性、复用性,实际上是非常容易的。

以上面的代码为例我们有两种实现方式:

1.在每个handleRegSuccess()函数中创建一个新的线程执行代码逻辑;

2.在UserController的register()函数中使用线程池来执行每个观察者的handleRegSuccess()函数。

对于第一种实现方式,频繁地创建和销毁线程比较耗时,并且并发线程数无法控制,创建过多的线程会导致堆栈溢出。第二种实现方式,尽管利用了线程池解决了第一种实现方式的问题,但线程池、异步执行逻辑都耦合在了register()函数中,增加了这部分业务代码的维护成本。

EventBus是一个框架,它提供了实现观察者模式的骨架代码。我们可以基于此框架,非常容易地在自己的业务场景中实现观察者模式,不需要从零开始开发。其中,Google Guava EventBus就是一个比较著名的EventBus框架,它不仅仅支持异步非阻塞模式,同时也支持同步阻塞模式,案例代码如下:

public class UserController {
    private UserService userService;
    private EventBus eventBus;

    private static final int DEFAULT_EVENTBUS_THREAD_POOL_SIZE = 20;

    public UserController() {
        //同步阻塞模式
        eventBus = new EventBus();
        // 异步非阻塞模式
        eventBus = new AsyncEventBus(Executors.newFixedThreadPool(DEFAULT_EVENTBUS_THREAD_POOL_SIZE));
        }

        public void setRegObservers(List<Object> observers) {
            for (Object observer : observers) {
                eventBus.register(observer);
            }
        }

    public Long register(String telephone, String password) {
        //省略输入参数的校验代码
        //省略userService.register()异常的try-catch代码
        long userId = userService.register(telephone, password);
        eventBus.post(userId);
        return userId;
    }
}

        public class RegPromotionObserver {
            private PromotionService promotionService;
            //依赖注入
            @Subscribe
            public void handleRegSuccess(long userId) {
                promotionService.issueNewUserExperienceCash(userId);
            }
        }


        public class RegNotificationObserver {
            private NotificationService notificationService;
            @Subscribe
            public void handleRegSuccess(long userId) {
                notificationService.sendInboxMessage(userId, "...");
            }
        }

如果需要带注释的spring源码或者了解更多行业技能请关注微信公众号 码农本农