1、观察者模式(Observer)
当对象之间出现一对多的关系时,使用观察者模式,主要思路是当一个对象的状态发生改变时,所有依赖于它的对象得到通知并作出更新。一个常见的例子:比如在微博中一个人拥有很多粉丝,每当他的微博状态更新时,会推送给粉丝更新状态。
观察者模式的结构:一个观察者抽象类及其子类,被观察对象类以及Client类(也就是图中的ObservePatternDemo类)
- 代码框架
被观察者类
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、访问者模式
访问者模式将作用于某个类中的元素操作分离出来封装成独立的类,即访问者类,使其在不改变类的前提下可以添加作用与这些元素的新操作,为类中的每个元素提供多种访问方式。当需要对一个对象结构中的对象进行很多不同且不相关的操作时,可以使用访问者模式。
- 访问者模式的结构
其中图中的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);
}
}
访问者模式的优点
- 扩展性好,能够在不修改对象结构中元素的情况下,为元素添加新的功能
- 复用性好,可以通过访问者来定义整个对象结构通用的功能
- 访问者模式将相关行为封装在一起,构成一个访问者,使得每一个访问者的功能比较单一
访问者模式的缺点
- 增加新的元素类困难;在访问者模式中,每增加一个新的元素类,都要在每一个具体访问类中增加相应的具体操作
- 破坏了类的封装性;访问者模式中具体元素对访问者公布细节,破坏了对象的封装性。