ps:本文系轉載文章,閱讀原文可獲取源碼,文章末尾有原文連接數組
ps:這一篇是寫備忘錄模式、中介者模式和解釋器模式ide
一、備忘錄模式測試
在保持封裝性的條件下,獲取一個對象的內部狀態,在其餘地方保存這個對象的狀態,當須要用到該對象狀態時就恢復到原先保存的狀態。this
備忘錄模式具備如下幾種角色:日誌
(1)發起人角色:記錄當前的內部狀態,具備建立備忘錄和恢復備忘錄的方法。code
(2)備忘錄角色:存儲發起人的內部狀態,在須要用到的時候返回這些內部狀態給發起人。對象
(3)管理者角色:對備忘錄進行管理,只提供保存與獲取備忘錄的方法。繼承
下面用代碼舉個例子:遞歸
(1)發起人角色,新建一個 Emp 類:接口
public class Emp {
private String ename;
private int age;
private double salary;
public Emp(String ename, int age, double salary) {
super(); this.ename = ename; this.age = age; this.salary = salary;
}
public EmpMemento memento() {
return new EmpMemento(this);
}
public void recovery(EmpMemento e) {
this.ename = e.getEname(); this.age = e.getAge(); this.salary = e.getSaraly();
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
(2)備忘錄角色,新建一個 EmpMemento 類:
public class EmpMemento {
private String ename;
private int age;
private double saraly;
public EmpMemento(Emp emp) {
ename = emp.getEname(); age = emp.getAge(); saraly = emp.getSalary();
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSaraly() {
return saraly;
}
public void setSaraly(double saraly) {
this.saraly = saraly;
}
}
(3)管理者角色,新建一個 CareTaker 類:
public class CareTaker {
private EmpMemento memento;
public EmpMemento getMemento() {
return memento;
}
public void setMemento(EmpMemento memento) {
this.memento = memento;
}
}
(4)客戶端進行測試調用:
CareTaker taker = new CareTaker(); Emp emp = new Emp("小周", 11, 300); System.out.println("第一次打印" + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary()); taker.setMemento(emp.memento()); System.out.println("已經保存了以前的數據,如今對數據進行修改"); emp.setEname("小二"); emp.setAge(19); emp.setSalary(99); System.out.println("第二次打印" + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary()); System.out.println("正在撤銷,恢復以前保存的數據"); emp.recovery(taker.getMemento()); System.out.println("第三次打印" + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary());
日誌打印以下所示:
圖片
首先一開始就實例化一個發起人角色 Emp,它的內部狀態就是 ename、age 和 salary 屬性,發起人角色建立備忘錄角色 EmpMemento,順便把本身的狀態賦值給 EmpMemento 的狀態,而後管理者角色 CareTaker 就把備忘錄角色 EmpMemento 存儲起來;當咱們把發起人角色 Emp 的狀態修改後,咱們要想恢復以前的狀態,就必須經過 CareTaker 的 getMemento 方法獲取發起人角色 Emp,並經過 Emp 的 recovery 方法最終實現恢復以前的狀態
;這個就像咱們用文件編輯文字同樣,咱們要想恢復上一次編輯的記錄,就按下 Ctrl + z 就能撤回到上一次的記錄了。
備忘錄模式雖然給用戶提供了一種能夠恢復狀態的機制,可使用戶可以比較方便地回到某個歷史的狀態;實現了信息的封裝,使得用戶不須要關心狀態的保存細節,且狀態信息都保存到備忘錄裏由管理者管理;可是若是類的成員變量過多,會佔用很大的資源,同時保存也會消耗必定的內存;改動也很麻煩,當發起人角色的狀態發生改變時,備忘錄角色的狀態也會發生改變。
二、中介者模式
用一箇中介對象來封裝一系列對象的交互過程,中介者使各對象能夠隱式的相互引用,使其耦合鬆散,並且改變它們之間的交互是獨立的。
中介者模式具備如下幾種角色:
(1)抽象中介者角色:具體中介者要實現的接口,定義了同事對象註冊和發送給同事對象信息的抽象方法。
(2)具體中介者角色:實現抽象中介者角色的子類,聲明一個容器來管理同事對象,協助同事類角色的交互,它依賴於同事角色。
(3)抽象同事類角色:聲明具體同事類角色要實現的接口,定義同事對象交互的抽象方法。
(4)具體同事類角色:抽象同事類角色的子類,實現抽象同事類角色全部的抽象方法,須要與其餘同事對象進行交互時,由中介者對象協助。
下面用代碼舉個例子:
(1)抽象中介者角色,新建一個 Mediator接口:
public interface Mediator {
public void register(String name,Department d); public void command(String name);
}
(2)抽象同事類角色,新建一個 Department接口:
public interface Department {
public void selfAction();
public void outAction();
}
(3)具體中介者角色,新建一個 President 類並實現 Mediator接口:
public class President implements Mediator{
private Map<String, Department> map = new HashMap<String, Department>();
@Override
public void register(String name, Department d) {
map.put(name, d);
}
@Override
public void command(String name) {
map.get(name).selfAction();
}
}
(4)具體同事類角色,新建一個 Market 類並實現 Department接口:
public class Market implements Department{
private Mediator mediator;
public Market(Mediator mediator) {
this.mediator = mediator; mediator.register("market", this);
}
@Override
public void selfAction() {
System.out.println("Market---跑市場");
}
@Override
public void outAction() {
System.out.println("Market---彙報工做,項目正在進度"); mediator.command("finacial"); mediator.command("development");
}
}
(5)具體同事類角色,新建一個 Finacial 類並實現 Department接口:
public class Finacial implements Department{
public Finacial(Mediator mediator) {
mediator.register("finacial", this);
}
@Override
public void selfAction() {
System.out.println("Finacial---數錢");
}
@Override
public void outAction() {
System.out.println("Finacial---彙報工做,出帳");
}
}
(6)具體同事類角色,新建一個 Development 類並實現 Department接口:
public class Development implements Department{
public Development(Mediator mediator) {
mediator.register("development", this);
}
@Override
public void selfAction() {
System.out.println("Development---專心科研項目");
}
@Override
public void outAction() {
System.out.println("Development---沒錢了,須要資金支持");
}
}
(7)客戶端進行測試調用:
Mediator mediator = new President(); Market market = new Market(mediator); new Finacial(mediator); new Development(mediator); market.selfAction(); market.outAction();
日誌打印以下所示:
圖片
首先實例化一箇中介者角色對象 mediator (實現類是 President),而後實例化具體同事類角色對象 new Market(mediator)、new Finacial(mediator) 和 new Development(mediator),並順便把這些實例化具體同事類角色對象註冊到中介者角色對象 mediator 中,此時具體同事類角色對象就會被保存到 Mediator 的實現類 President 的 Map 容器中;當 Market 調用 outAction 方法時,在該方法內部順便經過中介者 mediator 的 command 方法調用 Finacial 的 outAction 方法和 Development 的 outAction 方法,最終實現了中介者模式的效果。
中介者模式雖然使類變得簡單,將一對多轉化成了一對一的關聯,下降了各個類之間的耦合性,遵循迪米特原則;可是中介者會龐大,變得複雜難以維護,當同事類越多時,中介者就會越臃腫,每添加一個同事類,調用同事類的中介者頗有可能要修改。
三、解釋器模式
定義一個語言,定義它的文法表示,再定義一個解釋器,這個解釋器用來解釋語言中的句子。
解釋器模式具備如下幾種角色:
(1)抽象表達式角色:聲明解釋器的接口,規範解釋器的解釋行爲。
(2)終結符表達式角色:是抽象表達式的子類,用來實現文法中與終結符相關的操做。
(3)非終結符表達式角色:是抽象表達式的子類,用來實現文法中與非終結符相關的操做,它最終也是調用文法中與終結符相關的操做。
(4)環境角色:通常包含傳遞被全部解釋器共享的數據或是公共的功能。
下面用代碼舉個例子:
(1)抽象表達式角色,新建一個 Expression 接口:
public interface Expression {
public boolean interpret(String s);
}
(2)終結符表達式角色,新建一個 TerminalExpression 類並實現 Expression 接口:
public class TerminalExpression implements Expression {
private Set<String> set = new HashSet<String>();
public TerminalExpression(String[] data) {
for (int i = 0; i < data.length; i++) set.add(data[i]);
}
public boolean interpret(String info) {
if (set.contains(info)) { return true; } return false;
}
}
(3)非終結符表達式角色,新建一個 AndExpression 類並實現 Expression 接口:
public class AndExpression implements Expression {
private Expression city = null;
private Expression person = null;
public AndExpression(Expression city, Expression person) {
this.city = city; this.person = person;
}
public boolean interpret(String info) {
String s[] = info.split("的"); return city.interpret(s[0]) && person.interpret(s[1]);
}
}
(4)環境角色,新建一個 Context 類:
public class Context {
private String[] citys = { "深圳", "東莞" };
private String[] persons = { "老人", "學生", "兒童" };
private Expression cityPerson;
public Context() {
Expression city = new TerminalExpression(citys); Expression person = new TerminalExpression(persons); cityPerson = new AndExpression(city, person);
}
public void freeRide(String info) {
boolean b = cityPerson.interpret(info); if (b) { System.out.println("這是" + info + ",本次進園旅遊打5折!"); } else { System.out.println(info + ",不屬於享半價優惠人員,按原價收費"); }
}
}
(5)客戶端進行測試調用:
Context c = new Context(); c.freeRide("深圳的老人"); c.freeRide("東莞的年輕人"); c.freeRide("北京的婦女"); c.freeRide("上海的兒童"); c.freeRide("東莞的學生");
日誌打印以下所示:
圖片
首先實例化一個 Context 對象,在其構造方法中實例化2個終結符表達式角色對象 TerminalExpression 並傳遞字符串數組 citys 和 persons,建立好2個 TerminalExpression 對象以後,而後再建立非終結符表達式角色對象 AndExpression 並把2個 TerminalExpression 對象做爲參數傳入到它(AndExpression)的構造方法中;最後調用 Context 對象的 freeRide 方法,freeRide 方法的調用過程是這樣的 freeRide --> AndExpression.interpret--> TerminalExpression.interpret,最終由終結符表達式角色 TerminalExpression 來解釋語言中的句子;在這過程當中 AndExpression 的 interpret 方法將「的」字切割出來,而後用 city.interpret 方法判斷地方,person.interpret 判斷年齡段的人。
雖然解釋器模式在解釋器模式中使用類來展現語言的文法規則,經過繼承可讓拓展性變得更好,語法樹中的表達式節點類是類似的,比較好實現;可是它會引發類膨脹,採用遞歸調用方法層次太多會容易出現棧溢出,可利用場景比較少。