(備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式)
原文作者:終點 出處:Java之美[從菜鳥到高手演變]之設計模式四
首先還是上一下上篇開頭的那個圖:
本章講講第三類和第四類。
19、備忘錄模式(Memento)
Original類是原始類,里面有需要保存的屬性value及創建一個備忘錄類,用來保存value值。Memento類是備忘錄類,Storage類是存儲備忘錄的類,持有Memento類的實例,該模式很好理解。直接看源碼:
public class Original {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Original(String value) {
this.value = value;
}
public Memento createMemento(){
return new Memento(value);
}
public void restoreMemento(Memento memento){
this.value = memento.getValue();
}
}
public class Memento {
private String value;
public Memento(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public class Storage {
private Memento memento;
public Storage(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
測試類:
public class Test {
public static void main(String[] args) {
// 創建原始類
Original origi = new Original("egg");
// 創建備忘錄
Storage storage = new Storage(origi.createMemento());
// 修改原始類的狀態
System.out.println("初始化狀態為:" + origi.getValue());
origi.setValue("niu");
System.out.println("修改后的狀態為:" + origi.getValue());
// 回復原始類的狀態
origi.restoreMemento(storage.getMemento());
System.out.println("恢復后的狀態為:" + origi.getValue());
}
}
輸出:
初始化狀態為:egg
修改后的狀態為:niu
恢復后的狀態為:egg
簡單描述下:新建原始類時,value被初始化為egg,后經過修改,將value的值置為niu,最后倒數第二行進行恢復狀態,結果成功恢復了。其實我覺得這個模式叫“備份-恢復”模式最形象。
20、狀態模式(State)
核心思想就是:當對象的狀態改變時,同時改變其行為,很好理解!就拿QQ來說,有幾種狀態,在線、隱身、忙碌等,每個狀態對應不同的操作,而且你的好友也能看到你的狀態,所以,狀態模式就兩點:1、可以通過改變狀態來獲得不同的行為。2、你的好友能同時看到你的變化??磮D:
State類是個狀態類,Context類可以實現切換,我們來看看代碼:
package com.xtfggef.dp.state;
/**
* 狀態類的核心類
* 2012-12-1
* @author erqing
*
*/
public class State {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public void method1(){
System.out.println("execute the first opt!");
}
public void method2(){
System.out.println("execute the second opt!");
}
}
package com.xtfggef.dp.state;
/**
* 狀態模式的切換類 2012-12-1
* @author erqing
*
*/
public class Context {
private State state;
public Context(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void method() {
if (state.getValue().equals("state1")) {
state.method1();
} else if (state.getValue().equals("state2")) {
state.method2();
}
}
}
測試類:
public class Test {
public static void main(String[] args) {
State state = new State();
Context context = new Context(state);
//設置第一種狀態
state.setValue("state1");
context.method();
//設置第二種狀態
state.setValue("state2");
context.method();
}
}
輸出:
execute the first opt!
execute the second opt!
根據這個特性,狀態模式在日常開發中用的挺多的,尤其是做網站的時候,我們有時希望根據對象的某一屬性,區別開他們的一些功能,比如說簡單的權限控制等。
21、訪問者模式(Visitor)
訪問者模式把數據結構和作用于結構上的操作解耦合,使得操作集合可相對自由地演化。訪問者模式適用于數據結構相對穩定算法又易變化的系統。因為訪問者模式使得算法操作增加變得容易。若系統數據結構對象易于變化,經常有新的數據對象增加進來,則不適合使用訪問者模式。訪問者模式的優點是增加操作很容易,因為增加操作意味著增加新的訪問者。訪問者模式將有關行為集中到一個訪問者對象中,其改變不影響系統數據結構。其缺點就是增加新的數據結構很困難?!?From 百科
簡單來說,訪問者模式就是一種分離對象數據結構與行為的方法,通過這種分離,可達到為一個被訪問者動態添加新的操作而無需做其它的修改的效果。簡單關系圖:
來看看原碼:一個Visitor類,存放要訪問的對象,
public interface Visitor {
public void visit(Subject sub);
}
public class MyVisitor implements Visitor {
@Override
public void visit(Subject sub) {
System.out.println("visit the subject:"+sub.getSubject());
}
}
Subject類,accept方法,接受將要訪問它的對象,getSubject()獲取將要被訪問的屬性,
public interface Subject {
public void accept(Visitor visitor);
public String getSubject();
}
public class MySubject implements Subject {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getSubject() {
return "love";
}
}
測試:
public class Test {
public static void main(String[] args) {
Visitor visitor = new MyVisitor();
Subject sub = new MySubject();
sub.accept(visitor);
}
}
輸出:visit the subject:love
該模式適用場景:如果我們想為一個現有的類增加新功能,不得不考慮幾個事情:1、新功能會不會與現有功能出現兼容性問題?2、以后會不會再需要添加?3、如果類不允許修改代碼怎么辦?面對這些問題,最好的解決方法就是使用訪問者模式,訪問者模式適用于數據結構相對穩定的系統,把數據結構和算法解耦。
22、中介者模式(Mediator)
中介者模式也是用來降低類類之間的耦合的,因為如果類類之間有依賴關系的話,不利于功能的拓展和維護,因為只要修改一個對象,其它關聯的對象都得進行修改。如果使用中介者模式,只需關心和Mediator類的關系,具體類類之間的關系及調度交給Mediator就行,這有點像spring容器的作用。先看看圖:
User類統一接口,User1和User2分別是不同的對象,二者之間有關聯,如果不采用中介者模式,則需要二者相互持有引用,這樣二者的耦合度很高,為了解耦,引入了Mediator類,提供統一接口,MyMediator為其實現類,里面持有User1和User2的實例,用來實現對User1和User2的控制。這樣User1和User2兩個對象相互獨立,他們只需要保持好和Mediator之間的關系就行,剩下的全由MyMediator類來維護!基本實現:
public interface Mediator {
public void createMediator();
public void workAll();
}
public class MyMediator implements Mediator {
private User user1;
private User user2;
public User getUser1() {
return user1;
}
public User getUser2() {
return user2;
}
@Override
public void createMediator() {
user1 = new User1(this);
user2 = new User2(this);
}
@Override
public void workAll() {
user1.work();
user2.work();
}
}
public abstract class User {
private Mediator mediator;
public Mediator getMediator(){
return mediator;
}
public User(Mediator mediator) {
this.mediator = mediator;
}
public abstract void work();
}
public class User1 extends User {
public User1(Mediator mediator){
super(mediator);
}
@Override
public void work() {
System.out.println("user1 exe!");
}
}
public class User1 extends User {
public User1(Mediator mediator){
super(mediator);
}
@Override
public void work() {
System.out.println("user1 exe!");
}
}
public class User2 extends User {
public User2(Mediator mediator){
super(mediator);
}
@Override
public void work() {
System.out.println("user2 exe!");
}
}
測試類:
public class Test {
public static void main(String[] args) {
Mediator mediator = new MyMediator();
mediator.createMediator();
mediator.workAll();
}
}
輸出:
user1 exe!
user2 exe!
23、解釋器模式(Interpreter)
解釋器模式一般主要應用在OOP開發中的編譯器的開發中,所以適用面比較窄。
Context類是一個上下文環境類,Plus和Minus分別是用來計算的實現,代碼如下:
public interface Expression {
public int interpret(Context context);
}
public class Plus implements Expression {
@Override
public int interpret(Context context) {
return context.getNum1()+context.getNum2();
}
}
public class Minus implements Expression {
@Override
public int interpret(Context context) {
return context.getNum1()-context.getNum2();
}
}
public class Context {
private int num1;
private int num2;
public Context(int num1, int num2) {
this.num1 = num1;
this.num2 = num2;
}
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
}
public class Test {
public static void main(String[] args) {
// 計算9+2-8的值
int result = new Minus().interpret((new Context(new Plus()
.interpret(new Context(9, 2)), 8)));
System.out.println(result);
}
}
最后輸出正確的結果:3。
23種設計模式,完。