观察者模式学习笔记(详细)

观察者模式学习笔记(详细)

一、什么是观察者模式

观察者模式,是定义对象之间的一对多的关系,主要作用是减少对象之间的耦合度,分为两个角色

  1. 被观察者:其实就是发布者,发布消息通知所有的观察者
  2. 观察者:接到被观察者发布的消息做出相应的动作


上图中,左边一组是被观察者,右边一组是观察者

  • Subjecct:被观察者抽象类,拥有类成员ObserverList,和三个抽象方法
    ObserverList:存放所有的观察者对象
    addObserver():向ObserverList中添加观察者对象
    delObject():从ObserverList中删除观察者对象
    notifyObservers():通知所有的观察者对象

  • SubjectItem:具体的被观察者类,继承Subject接口,有具体的动作方法,调用父类的notifyObject()方法通知所有的观察者

  • Observer:观察者接口,有一个抽象方法update(),供被观察者调用

  • ObserverItem:具体的观察者类,实现Observer类,实现update()方法

二、使用场景

游戏中,被观察者主角有所动作就通知观察者们
支付中,一个商品购买成功,需要执行许多操作(更新订单,发送邮件,更新账户…),这时就可以使用观察者模式来减少耦合
再比如,关注动态,动态更新,需要发送通知给所有的关注者

三、具体实现

简单的一个冒险游戏,勇者做为被观察者,观察者有怪物,食物,NPC
当勇者移动碰到怪物时血量减1,碰到食物时血量加1,碰到NPC时展开剧情

  1. 编写Observer接口
	public interface Observer {
		public void update();
	}
  1. 编写Subject抽象类
	public abstract class Subject {
		//观察者集合
    	private List<Observer> observerList = new ArrayList<>();
    			
		//添加观察者
	    public void addObserver(Observer observer){
    	   observerList.add(observer);
	    }
		
		//删除观察者
	    public void delObserver(Observer observer){
	        observerList.remove(observer);
	    }
			
		//通知所有观察者
	    public void notifyObservers(){
	        for(Observer observer : observerList){
	            observer.update();
	        }
	    }
	    
	}

observerList集合存放了观察者接口,不直接存放观察者类
notifyObservers()方法遍历observerList集合,调用update()方法
通过抽象层减少耦合

  1. 编写勇者类(被观察者)
 	public class Hero extends Subject {
	
	    static int X = 0;
        static int Y = 0;
	
		//勇者移动
	    public void move(int x, int y){
	        X = x;
	        Y = y;
	        super.notifyObservers();
	    }
	
	}

Hero类有move()方法,让勇者移动并调用父类的notifyObservers()方法通知所有的观察者

  1. 编写怪物类(观察者)
	public class Monster implements Observer {
	
		static int X = 5;
	    static int Y = 7;
	
	    @Override
	    public void update() {
	        if(Hero.X == X && Hero.Y == Y){
	            System.out.println("怪物攻击勇者!");
	        }
	    }
	    
	}  

Monster类实现Observer接口,实现具体的update()方法

  1. 编写食物类(观察者)
	public class Food implements Observer {
		
	    static int X = 8;
	    static int Y = 8;
	
	    @Override
	    public void update() {
	        if(Hero.X == X && Hero.Y == Y){
	            System.out.println("勇者吃到了食物,血量加1!");
	        }
	    }
	    
	}  

Food类实现Observer接口,实现具体的update()方法

  1. 编写npc类(观察者)
	public class Npc implements Observer {
	
	    static int X = 15;
	    static int Y = 20;
	
	    @Override
	    public void update() {
	        if(Hero.X == X && Hero.Y == Y){
	            System.out.println("勇者遇到NPC,剧情展开!");
	        }
	    }
	
	}

Npc类实现Observer接口,实现具体的update()方法

  1. 编写执行类
	public class Run {
		
	    public static void main(String[] args){
	        //初始化对象
	        Hero hero = new Hero();
	        Monster monster = new Monster();
	        Food food = new Food();
	        Npc npc = new Npc();
	
	        //添加观察者
	        hero.addObserver(monster);
	        hero.addObserver(food);
	        hero.addObserver(npc);
	        //勇者移动,遇到怪物
	        hero.move(5,7);
	        //勇者移动,吃到食物
	        hero.move(8,8);
	        //勇者移动,遇到npc
	        hero.move(15,20);
	    }
	
	}

勇者移动时通知了所有已注册的观察者,执行各自的update方法

  1. 运行结果

四、总结

  • 优点:
    使用抽象的方式来减少被观察者和观察者之间的耦合,可以方便的增加观察者

  • 缺点:
    如果被观察者有过多的直接观察者和间接观察者的话,会花费更多的时间,如果观察者之间存在循环依赖的话,会导致他们直接进行循环调用,最终导致系统崩溃
    观察者可以知道被观察者发生的变化,但是无法知道被观察者是如何发生的变化

猜你喜欢

转载自blog.csdn.net/qq_43247353/article/details/107801646