Java設計模式簡介(四):行為型模式(下)
其實每個設計模式都是很重要的一種思想,看上去很熟,其實是因為我們在學到的東西中都有涉及,儘管有時我們並不知道,其實在Java本身的設計之中處處都有體現,像AWT、JDBC、集合類、IO管道或者是Web框架,裡面設計模式無處不在。因為我們篇幅有限,很難講每一個設計模式都講的很詳細。
本章講講第三類和第四類。
19、備忘錄模式(Memento):
主要目的是儲存一個物件的某個狀態,以便在適當的時候恢復物件,個人覺得叫備份模式更形象些,通俗的講下:假設有原始類A,A中有各種屬性,A可以決定需要備份的屬性,備忘錄類B是用來儲存A的一些內部狀態,類C呢,就是一個用來儲存備忘錄的,且只能儲存,不能修改等操作。做個圖來分析一下:
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、你的好友能同時看到你的變化。看圖:
State類是個狀態類,Context類可以實現切換,我們來看看程式碼:
package com.xtfggef.dp.state;
/**
* 狀態類的核心類
*/
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
*/
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 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!
中介者模式的優點:
(1)適當地使用中介者模式可以避免同事類之間的過度耦合,使得各同事類之間可以相對獨立地使用。
(2)使用中介者模式可以將物件間一對多的關聯轉變為一對一的關聯,使物件間的關係易於理解和維護。
(3)使用中介者模式可以將物件的行為和協作進行抽象,能夠比較靈活的處理物件間的相互作用。
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種設計模式做全面的闡述,此處讀者可將它作為一個理論基礎去學習,通過這四篇博文,先基本有個概念,雖然我講的有些簡單,但基本都能說明問題及他們的特點,如果對哪一個感興趣,可以繼續深入研究!
原文連結:
https://blog.csdn.net/zhangerqing/article/details/8245537