设计模式系列-观察者模式,访问者模式
观察者模式
observer.pngSubject被观察者:能够动态地增加、取消观察者,职责是管理观察者并通知观察者。
Observer观察者: 接收到消息后,进行相应的操作。
ConcreteSubject:具体的被观察者
ConcreteObserver:具体的观察者
//抽象被观察者
public abstract class Subject {
//定义一个观察者数组
private Vector obsVector = new Vector();
//增加一个观察者
public void addObserver(Observer o){
this.obsVector.add(o);
}
//删除一个观察者
public void delObserver(Observer o){
this.obsVector.remove(o);
}
//通知所有观察者
public void notifyObservers(){
for(Observer o:this.obsVector){
o.update();
}
}
}
//具体被观察者
public class ConcreteSubject extends Subject {
//具体的业务
public void doSomething(){
//something
super.notifyObservers();
}
}
//观察者接口
public interface Observer {
//更新方法
public void update();
}
//具体观察者
public class ConcreteObserver implements Observer {
//实现更新方法
public void update() {
System.out.println("接收到信息,并进行处理!");
}
}
public class Client {
public static void main(String[] args) {
//创建一个被观察者
ConcreteSubject subject = new ConcreteSubject();
//定义一个观察者
Observer obs= new ConcreteObserver();
//观察者观察被观察者
subject.addObserver(obs);
//观察者开始活动了
subject.doSomething();
}
}
观察者模式的使用场景:
建立一套触发机制。
观察者模式的缺点在:
观察者模式需要考虑一下开发效率和运行效率问题
访问者模式
数据操作与数据结构分离的设计模式。是23中设计模式中比较复杂的一个,使用频率不高但是一旦需要使用,就是迫切的需要。
定义:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
visitor.jpg角色:
Visitor——抽象访问者:程序中就是visit方法的参数定义哪些对象是可以被访问的
ConcreteVisitor——具体访问者:它影响访问者访问到一个类后该怎么干,要做什么事情(CEOVisitor,CTOVisitor)
Element——抽象元素:声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的(Staff)
ConcreteElement——具体元素:实现accept方法,通常是visitor.visit(this),基本上都形成了一种模式了(Engineer,Manager)
ObjectStruture——结构对象(可选):元素产生者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色。(Report)
//员工基类
public abstract class Staff {
public String name;
public int kpi;
public Staff(String name){
this.name = name;
kpi = new Random().nextInt(10);
}
public abstract void accept(Visitor visitor);
}
//产品经理
public class Manager extends Staff{
public Manager(String name) {
super(name);
}
//一年内的产品数量
public int getProducts(){
return 100;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
//工程师
public class Engineer extends Staff{
public Engineer(String name) {
super(name);
}
//一年的代码行数
public int getCodeLine(){
return 10000;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
//访问者接口
public interface Visitor {
void visit(Engineer engineer);
void visit(Manager manager);
}
public class Report {
List<Staff> list = new ArrayList<>();
public Report(){
list.add(new Manager("zhang3"));
list.add(new Engineer("wang5"));
list.add(new Engineer("li4"));
list.add(new Engineer("liuermazi"));
}
public void showReport(Visitor visitor){
for (Staff staff : list){
staff.accept(visitor);
}
}
}
public class CEOVisitor implements Visitor{
@Override
public void visit(Engineer engineer) {
System.out.print("kpi: " +engineer.kpi);
}
@Override
public void visit(Manager manager) {
System.out.print("kpi: " + manager.kpi);
}
}
public class CTOVisitor implements Visitor {
@Override
public void visit(Engineer engineer) {
System.out.print("code: " + engineer.getCodeLine());
}
@Override
public void visit(Manager manager) {
System.out.print("product: "+ manager.getProducts());
}
}
public class Client {
public static void main(String[] args) {
Report report = new Report();
//CEO访问者,给CEO看的报表
report.showReport(new CEOVisitor());
//CTO访问者,给CTO看的报表
report.showReport(new CTOVisitor());
}
}
思考:
抽象Staff中使用了Visitor,Visitor依赖于Engineer和Manager(具体的Staff),这样间接导致依赖于具体的Staff,这样设计好不好?
如果这样写呢?
public abstract class Staff {
public String name;
public int kpi;
public Staff(String name){
this.name = name;
kpi = new Random().nextInt(10);
}
public void accept(Visitor visitor){
visitor.visit(this)
}
}
//访问者接口
public interface Visitor {
void visit(Staff staff);
}
public class CEOVisitor implements Visitor{
@Override
public void visit(Staff staff) {
if(staff instanceof Manager){
Manager manager = (Manager)staff;
System.out.print("产品经理kpi: " +manager.kpi);
}else if(staff instanceof Engineer){
Engineer engineer = (Engineer)staff;
System.out.print("工程师kpi: " +engineer.kpi);
}
}
}
这样写就不依赖于具体的元素了,也减少了每次调用visit方法。但是增加的是if-else的嵌套以及类型的强制转换,当类型较多时也会变得比较难以维护。各有利弊吧。