初探设计模式之【观察者】
一、前言
在现实生活中,观察者往往是主动的、被观察者是被动的。比如,要小王要向领导汇报一件事情,因而时刻关注着领导的工位,看领导有没有来公司。如果领导一直不来,对于小王来说,可能有点烦,这领导也太不省心了…。我们可以这么做,小王事先与领导沟通,然后领导告诉小王说:”今天会晚一些,到公司了会告诉你“,那这样,小王就省心多了,不用一直盯着这件事。
相应的,在软件开发中,也有类似的场景,比如在电商业务中,用户想要购买某件商品,可是商品暂时无货了,着急的用户可能会每隔一个小时跑来这个商品的页面刷新,看是不是有货了,这就是一种观察者的主动行为,服务器作为被观察者是被动的,如果在大促期间这么做的用户非常多,不仅用户体验不好,服务器还要承受特别大的压力,对双方都不好。而如果产品经理在商详中增加了【订阅到货】功能(想购买的用户点击订阅商品到货通知,代商品到货后,通知所有订阅者),就可以解决这些弊端了。
二、实现
首先是观察者基类:
public abstract class Buyer {
private String name;
public Buyer(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void inform(Product product);
}
观察者的核心方法是一个抽象的通知方法,统一被观察者通知观察者的方式。
商品类:
public class Product {
public String name;
public int count;
public Product() {
}
public Product(String name, int count) {
this.name = name;
this.count = count;
}
}
然后我们实现一些观察者,这里是具体的买家
手机黄牛:(遇见手机,有多少买多少)
/**
* 黄牛 专门倒卖手机 有多少收多少
*/
public class Vendor extends Buyer {
public Vendor(String name) {
super(name);
}
@Override
public void inform(Product product) {
if (product.name.contains("手机")) {
if (product.count > 0) {
System.out.println(getName() + "买光了" + product.count + "台" + product.name);
product.count = 0;
} else {
System.out.println(getName() + ":" + product.name + "已经被抢购一空");
}
}
}
}
手机爱好者:
public class PhoneBuyer extends Buyer {
public PhoneBuyer(String name) {
super(name);
}
@Override
public void inform(Product product) {
if (product.name.contains("手机")) {
if (product.count > 0) {
product.count--;
System.out.println(getName() + "买了一台" + product.name);
} else {
System.out.println(getName() + ":" + product.name + "已经被抢购一空");
}
}
}
}
爱读书的人:
public class Reader extends Buyer {
public Reader(String name) {
super(name);
}
@Override
public void inform(Product product) {
if (product.name.contains("书")) {
if (product.count > 0) {
product.count--;
System.out.println(getName() + "买走了一本" + product.name);
} else {
System.out.println(getName() + ":" + product.name + "已经被抢购一空");
}
}
}
}
购物狂,什么都买
public class Shopaholic extends Buyer {
public Shopaholic(String name) {
super(name);
}
@Override
public void inform(Product product) {
if (product.count > 0) {
product.count--;
System.out.println(getName() + "买了一个" + product.name);
} else {
System.out.println(getName() + ":" + product.name + "已经被抢购一空");
}
}
}
商店类:
public class Shop {
private final List<Buyer> buyers = new ArrayList<>();
private Product product;
public void register(Buyer buyer) {
if (!buyers.contains(buyer)) {
buyers.add(buyer);
}
}
public void unRegister(Buyer buyer) {
buyers.remove(buyer);
}
public void setProduct(Product product) {
this.product = product;
notifyBuyers();
}
private void notifyBuyers() {
for (Buyer buyer : buyers) {
buyer.inform(product);
}
}
}
商店类维护了一个买家列表,商品到货后,通知所有买家,化被动为主动。
最后是调用处:
public static void main(String[] args) {
Shop shop = new Shop();
shop.register(new PhoneBuyer("果粉"));
shop.register(new Reader("读书人"));
shop.register(new Vendor("黄牛党"));
shop.register(new Shopaholic("剁手党"));
shop.setProduct(new Product("苹果手机", 100));
System.out.println("==============");
shop.setProduct(new Product("书:追风筝的人", 5));
System.out.println("==============");
shop.setProduct(new Product("大白菜", 100));
}
输入日志如下:
果粉买了一台苹果手机
黄牛党买光了99台苹果手机
剁手党:苹果手机已经被抢购一空
读书人买走了一本书:追风筝的人
剁手党买了一个书:追风筝的人
剁手党买了一个大白菜
三、总结
作为一种发布/订阅式模型,观察者模式被大量应用于具有一对多关系对象结构的场景,它支持多个观察者订阅一个目标主题。一旦目标主题的状态发生变化,目标对象便主动进行广播,即刻对所有订阅者发布全员消息通知。