观察者模式和访问者模式

1、观察者模式(Observer)

当对象之间出现一对多的关系时,使用观察者模式,主要思路是当一个对象的状态发生改变时,所有依赖于它的对象得到通知并作出更新。一个常见的例子:比如在微博中一个人拥有很多粉丝,每当他的微博状态更新时,会推送给粉丝更新状态。
观察者模式的结构:一个观察者抽象类及其子类,被观察对象类以及Client类(也就是图中的ObservePatternDemo类)
观察者模式和访问者模式_第1张图片

  • 代码框架

被观察者类

public class Person(
	private List<Observer> observers=new ArrayList<>();//观察者列表
	private String state;

	public void SetState(String state){//状态的更新
		this.state=state;
		notifyAll();
	}
	public String GetState(){
		return this.state;
	}

	private void notifyAll(){//通知观察者被观察者的状态变化
		for(Observers observer:observers){
			observer.update();
		}
	}
	
	public void attach(Observer observer){//向观察者列表中添加观察者
		observers.add(observer);
	}

观察者抽象类及其子类

public abstract class Observer{
	protected Person person;
	public abstract void update();
}

public class ObserverOne extends Observer{//观察者一
	public ObserverOne(Person person){//delegation将观察者和被观察者连接
		this.person=person;
		this.person.attach(this);
	}
	@Override
	public void update(){//观察者信息的更新,可通过GetState函数实现
		...
	}
}

public class ObserverTwo extends Observer{//观察者二
	...
}
	

Client类

public Class Client{
	public static void main(String[] args){
		Person person;
		new ObserverOne(person);
		new ObserverTwo(person);
		person.SetState("...");//不直接调用观察者函数,通过被观察者的delegation
		...
	}
}
		
		
  • Java的util包中已经实现了该模式,提供了Observeable类,在构造被观察者类时直接派生子类即可;还提供了Observer观察者接口;

2、访问者模式

访问者模式将作用于某个类中的元素操作分离出来封装成独立的类,即访问者类,使其在不改变类的前提下可以添加作用与这些元素的新操作,为类中的每个元素提供多种访问方式。当需要对一个对象结构中的对象进行很多不同且不相关的操作时,可以使用访问者模式。

  • 访问者模式的结构
观察者模式和访问者模式_第2张图片

其中图中的Visitor就是访问者抽象类,其子类中定义需要扩展的操作,且对于不同元素实现。Element就是作用的ADT,而ObjectStructure就是多个元素形成的数据结构,如列表,集合等。

  • 代码框架

以商店购买货物为例。不同的元素就是不同的商品,而访问者类中定义不同的购买金额。首先定义不同的元素类和接口类。

public interface Element{
	public int accept(Visitor visitor);//处理数据的功能
}

public class Book implements Elements{//第一个元素类
	private doublie price;
	public Book(double price){
		this.price=price;
	}
	public double getPrice(){
		return this.price;
	}
	@Override
	public int accept(Visitor visitor){
		visitor.visit(this);//delegate到外部传入的visitor
	}
	...
}

public class Fruit implements Elements{//第二种元素类
	private doublie price;
	public Fruit(double price){
		this.price=price;
	}
	public double getPrice(){
		return this.price;
	}
	@Override
	public int accept(Visitor visitor){
		visitor.visit(this);//delegate到外部传入的visitor
	}
	...
}

定义Visitor抽象类和其子类(对于不同元素类的不同的操作方法)

public interface Visitor{
	double visit(Book book);
	double visit(Fruit fruit);	
}

public VisitorOne implements Visitor{//其中一种的Visitor的实现
	@Override
	public double visit(Book book){
		double cost=0;
		if(book.getPrice()>50){
			cost=book.getPrice()*0.8;
		}
		else cost=book.getPrice();
	}
	@Override
	public double visit(Fruit fruit){
		double cost=0;
		if(fruit.getPrice()>10){
			cost=book.getPrice()*0.9;
		}
		else cost=book.getPrice();
	}
}
			

最后在Client类中调用元素的accept函数计算通过visit方法求得的金额总和。

public class Client{
	public static void main(String[] args){
		Element[] items=new Element{new Book(100),new Fruit(50)};
		Visitor visitor=new VisitorOne();
		double sum=0;
		for(Element item:items){
			sum+=item.accept(visitor);
		}
		System.out.println("Cost: "+sum);
	}
}

访问者模式的优点

  • 扩展性好,能够在不修改对象结构中元素的情况下,为元素添加新的功能
  • 复用性好,可以通过访问者来定义整个对象结构通用的功能
  • 访问者模式将相关行为封装在一起,构成一个访问者,使得每一个访问者的功能比较单一

访问者模式的缺点

  • 增加新的元素类困难;在访问者模式中,每增加一个新的元素类,都要在每一个具体访问类中增加相应的具体操作
  • 破坏了类的封装性;访问者模式中具体元素对访问者公布细节,破坏了对象的封装性。

你可能感兴趣的:(软件构造)