觀察者模式
Subject被觀察者:能夠動態地增加、取消觀察者,職責是管理觀察者并通知觀察者。
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——抽象訪問者:程序中就是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的嵌套以及類型的強制轉換,當類型較多時也會變得比較難以維護。各有利弊吧。