java設計模式之——策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式(行為型)【讀書筆記】
一、策略模式
定義:定義了演算法家族,分別封裝起來,讓他們之間可以互相替換,此模式讓演算法的變化,不會影響到演算法的客戶。
使用場景:策略模式是一種定義一系列演算法的方法,從概念上看,所有的這些演算法完成的都是相同的工作,只是實現不同,它可以以相同的方式呼叫所有的演算法,減少了各種演算法類與使用演算法類之間的耦合。策略模式的strategy類層次定義了一系類的可供重用的演算法或行為。繼承有助於析取出這些演算法的中的公共功能。策略模式的優點是簡化了單元測試,因為每個演算法都有自己的類,可以通過自己的介面進行單獨測試。
示意圖:
例項:
演算法類介面和實現類:
package com.softline.strategy; public interface IStrategy { public void strateMethod(); } package com.softline.strategy; public class StrategyA implements IStrategy { @Override public void strateMethod() { // TODO Auto-generated method stub System.out.println("This is strategyA!"); } } package com.softline.strategy; public class StrategyB implements IStrategy { @Override public void strateMethod() { // TODO Auto-generated method stub System.out.println("this is strategyB!"); } }
上下文實現類:
package com.softline.strategy;
public class Context {
private IStrategy strategy;
public Context(IStrategy strategy){
this.strategy=strategy;
}
public void strategyMethod(){
strategy.strateMethod();
}
}
客戶端:
package com.softline.strategy; public class Client { public static void main(String[] args) { Context context = new Context(new StrategyA()); context.strategyMethod(); } } windows: This is strategyA!
二、模板方法模式
定義:定義了一個類中演算法的骨架,而將一些步驟延遲到y子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。
使用場景:模板模式是通過把不變的行為搬到超類,去除子類中重複程式碼來體現它的優勢。當不變和可變的行為在方法的子類實現中混合在一起的時候,不變的行為就會在子類中重複出現。我們通過模板方法模式把這些行為搬到單一的地方,這樣就幫助子類擺脫重複的不變的行為的糾纏。
示意圖:
例項:
模板抽象類以及對應實現類:
package com.softline.TemplateMethod;
public abstract class ICookTemplate {
public final void cook(){
this.pourOil();
this.heatOil();
this.pourVegetable();
this.pourSauce();
this.fly();
}
public void pourOil(){
System.out.println("倒油...");
}
public void heatOil(){
System.out.println("熱油...");
}
public void pourVegetable(){
System.out.println("到蔬菜...");
}
public void pourSauce(){
System.out.println("到調料...");
}
public void fly(){
System.out.println("翻炒...");
}
}
package com.softline.TemplateMethod;
public class Qingcai extends ICookTemplate {
@Override
public void pourVegetable(){
System.out.println("倒青菜...");
}
@Override
public void pourSauce(){
System.out.println("倒鹽...");
}
}
package com.softline.TemplateMethod;
public class Carrot extends ICookTemplate {
public void pourVegetable(){
System.out.println("倒胡蘿蔔...");
}
public void pourSauce(){
System.out.println("倒胡椒粉...");
}
}
測試客戶端
package com.softline.TemplateMethod;
public class Client {
public static void main(String[] args) {
Qingcai qingcai = new Qingcai();
Carrot carrot = new Carrot();
qingcai.cook();
System.out.println("-----------------------");
carrot.cook();
}
}
三、觀察者模式
定義:定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽某一個主題物件。這個主題物件在狀態發生變化時,會通知所有觀察者物件使他們能夠自動更新自己。
使用場景:將一個系統分割成一系列相互協作的類有一個很不好的副作用,那就是需要維護相關物件之間的一致性。我們不希望為了維護一致性而使各類之間緊密耦合,這樣會給維護、擴充套件、重用帶來不便。當一個物件的改變需要改變其他物件時,而且他並不知道需要改變多少物件時需要使用觀察者模式。一個抽象模型有兩個方面,其中一方面依賴於另一個方面,這時使用觀察者模式可以將這兩者封裝在獨立的物件當中使他們各自獨立的改變和複用。觀察者模式所做的工作就是解除耦合,讓耦合雙方都依賴於抽象,而不是依賴於具體。從而使各自的變化都不會影響另一邊的變化。
示意圖:
例項:
觀察者實現介面、主題類介面、展示介面
package com.softline.observer;
public interface Observer {
public void update(float temp);
}
package com.softline.observer;
public interface ISubject {
public void registerObserver(Observer observer);
public void removeObserver(Observer observer);
public void notifyObserver();
}
package com.softline.observer;
public interface IDisplayElement {
public void display();
}
主題實現類
package com.softline.observer;
import java.util.ArrayList;
public class WeatherStation implements ISubject {
private ArrayList<Observer> observers;
private float temp;
public WeatherStation(){
observers = new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer observer) {
// TODO Auto-generated method stub
if(!observers.contains(observer))
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
// TODO Auto-generated method stub
int i = observers.indexOf(observer);
if(i>=0)
observers.remove(i);
}
@Override
public void notifyObserver() {
// TODO Auto-generated method stub
for(int i=0;i<observers.size();i++){
Observer observer = (Observer)observers.get(i);
observer.update(temp);
}
}
public void setMeasurements(float temp){
this.temp = temp;
System.out.println("氣象站的溫度為:"+temp+"0C");
notifyObserver();
}
}
展示類
package com.softline.observer;
public class Display implements Observer,IDisplayElement {
private float temp;
private ISubject weatherStation;
public Display(ISubject weatherStation){
this.weatherStation=weatherStation;
weatherStation.registerObserver(this);
}
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println("當前溫度是:"+temp+"0C");
}
@Override
public void update(float temp) {
// TODO Auto-generated method stub
this.temp=temp;
display();
}
}
客戶端
package com.softline.observer;
public class Client {
public static void main(String[] args) {
WeatherStation ws = new WeatherStation();
Display diaplay = new Display(ws);
ws.setMeasurements(23);
ws.setMeasurements(24);
ws.setMeasurements(25);
}
}
四、迭代子模式
定義:提供一種方法順序訪問一個聚合物件中各個元素,而又不暴露該物件內部表示。
使用場景:當訪問一個聚集物件,而且不管這些物件是什麼都需要遍歷的時候,就應該考慮使用迭代器模式。需要對聚集有多種方式遍歷時,可以考慮使用迭代器模式。
示意圖:
例項:
定義Iterator介面、IContainer介面
package com.softline.Iterator;
public interface Iterator {
public Object first();
public Object previous();
public Object next();
public boolean hasNext();
}
package com.softline.Iterator;
public abstract class IContainer {
public abstract Iterator iterator();
public abstract void put(Object object);
}
定義對應的實現類:
package com.softline.Iterator;
import java.util.List;
public class MyIterator implements Iterator {
private List<Object> list;
private int index = 0;
public MyIterator(List<Object> list){
this.list = list;
}
@Override
public Object first() {
// TODO Auto-generated method stub
if(this.list.size()<=0){
return null;
}else{
return this.list.get(0);
}
}
@Override
public Object previous() {
// TODO Auto-generated method stub
if((this.index-1)<0){
return null;
}else{
return this.list.get(index--);
}
}
@Override
public Object next() {
// TODO Auto-generated method stub
if(this.index >=this.list.size()){
return null;
}else{
return this.list.get(index++);
}
}
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
if(this.index<this.list.size()){
return true;
}
return false;
}
}
package com.softline.Iterator;
import java.util.ArrayList;
import java.util.List;
public class MyContainer extends IContainer {
private List<Object> list;
public MyContainer(){
this.list = new ArrayList<Object>();
}
@Override
public Iterator iterator() {
// TODO Auto-generated method stub
return new MyIterator(list);
}
@Override
public void put(Object object) {
// TODO Auto-generated method stub
this.list.add(object);
}
}
定義測試客戶端
package com.softline.Iterator;
public class Client {
public static void main(String[] args) {
MyContainer myContainer = new MyContainer();
myContainer.put("1");
myContainer.put("22");
myContainer.put("333");
Iterator iterator = myContainer.iterator();
while(iterator.hasNext()){
System.out.println(String.valueOf(iterator.next()));
}
}
}
五、責任鏈模式
定義:使多個物件都有機會處理請求,從而避免請求的傳送者和接受者之間的耦合關係。將這個物件連成一條鏈,並沿著這條鏈傳遞改請求,知道有個物件處理它為止。
使用場景:當客戶提出一個請求時,請求是沿鏈傳遞直至有一個ConcretreHandler物件負責處理它。接受者和傳送者都沒有明確的資訊,且鏈中的自己並不知道鏈的結構。結果是職責鏈可簡化物件的相互連線,他們僅需保持一個指向其後繼者的引用,而不需要保持他們候選接受者的引用。可以隨時的增加或處理一個請求的結構。增強了給物件指派職責的靈活性。一個請求極有可能到了請求的末端都得不到處理,或者因為沒有正確的配置而得不到處理。
示意圖:
例項:
責任連結口
package com.softline.responsibility;
public abstract class LeaderHandler {
private LeaderHandler hander = null;
public abstract void disposeLeave();
public LeaderHandler setHandler(LeaderHandler hander){
this.hander=hander;
return this.hander;
}
protected void doChain(){
if(this.hander!=null){
this.hander.disposeLeave();
}
}
}
責任鏈實現類
package com.softline.responsibility;
public class HeadHandler extends LeaderHandler {
@Override
public void disposeLeave() {
// TODO Auto-generated method stub
System.out.println("處理車的Head!");
this.doChain();
}
}
package com.softline.responsibility;
public class BodyHandler extends LeaderHandler {
@Override
public void disposeLeave() {
// TODO Auto-generated method stub
System.out.println("處理身體body!");
this.doChain();
}
}
package com.softline.responsibility;
public class TailHandler extends LeaderHandler {
@Override
public void disposeLeave() {
// TODO Auto-generated method stub
System.out.println("處理結尾!");
this.doChain();
}
}
客戶端
package com.softline.responsibility;
public class Client {
public static void main(String[] args) {
LeaderHandler headHandler = new HeadHandler();
LeaderHandler bodyHandler = new BodyHandler();
LeaderHandler tailHandler = new TailHandler();
headHandler.setHandler(bodyHandler).setHandler(tailHandler);
headHandler.disposeLeave();
}
}
window:
處理車的Head!
處理身體body!
處理結尾!
六、命令模式
定義:將一個請求封裝為一個物件,從而使你可以使用不同的請求對客戶進行引數化:對請求排隊或記錄請求日誌,以及支援可撤銷的操作。
使用場景:他能較容易的設計一個命令佇列;在需要的情況下,可以較容易的將命令記入日誌;允許接受請求的一方決定是否要否決請求。可以容易的實現對請求的撤銷重做;由於加進新的具體的命令類而不影響其他類,因此增加新的命令類很容易。命令模式把請求一個物件與知道怎麼執行一個操作的物件分隔開。
敏捷開發原則告訴我們,不要為程式碼新增基於猜測的、實際不需要的功能。如果不清楚一個系統是否需要命令模式,一般就不要著急去實現它,事實上,在需要的時候通過重構去實現這個模式並不困難,只有在真正需要如撤銷、恢復操作等功能時,把原來的模式重構成命令模式才有意義。
示意圖:
例項:
定義家電介面,命令介面
package com.softline.Command;
public interface ICommand {
public void execute();
public void undo();
}
package com.softline.Command;
public interface IHouseholdApplication {
public void on();
public void off();
}
定義家電實現類
package com.softline.Command;
public class Light implements IHouseholdApplication {
@Override
public void on() {
// TODO Auto-generated method stub
System.out.println("light on");
}
@Override
public void off() {
// TODO Auto-generated method stub
System.out.println("light off");
}
}
package com.softline.Command;
public class TV implements IHouseholdApplication {
@Override
public void on() {
// TODO Auto-generated method stub
System.out.println("TV on");
}
@Override
public void off() {
// TODO Auto-generated method stub
System.out.println("TV off");
}
}
定義命令實現類
package com.softline.Command;
public class LightCommand implements ICommand {
private IHouseholdApplication application;
public LightCommand(IHouseholdApplication application){
this.application=application;
}
@Override
public void execute() {
// TODO Auto-generated method stub
application.on();
}
@Override
public void undo() {
// TODO Auto-generated method stub
application.off();
}
}
package com.softline.Command;
public class TVCommand implements ICommand {
private IHouseholdApplication application;
public TVCommand(IHouseholdApplication application){
this.application=application;
}
@Override
public void execute() {
// TODO Auto-generated method stub
application.on();
}
@Override
public void undo() {
// TODO Auto-generated method stub
application.off();
}
}
定義命令實現類
package com.softline.Command;
import java.util.ArrayList;
import java.util.List;
public class Phone {
private List<ICommand> list;
public Phone(){
this.list = new ArrayList<ICommand>();
}
public void setCommand(ICommand command){
this.list.add(command);
}
public void onButtonWasPushed(int index){
list.get(index).execute();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Phone phone = new Phone();
ICommand lightCommand = new LightCommand(new Light());
ICommand tvCommand = new TVCommand(new TV());
phone.setCommand(lightCommand);
phone.setCommand(tvCommand);
phone.onButtonWasPushed(0);
phone.onButtonWasPushed(1);
}
}
windows:
light on
TV on
七、備忘錄模式
定義:在不破壞封裝性的前提下,捕獲一個物件內部的狀態,並在這個物件之外儲存這個狀態。這樣以後就可將改物件恢復到原先儲存的狀態。
使用場景:要儲存的細節給封裝在了Memento中,哪一天要更改儲存的細節也不影響客戶端了。Memento模式比較適用於比較複雜的,但需要維護或記錄屬性的歷史的類,或者眾多屬性中的一小部分,Originator可以根據儲存的Memento資訊還原到前一狀態。如果在某個系統中使用命令模式時,需要實現命令的撤銷功能,那麼命令模式可以使用備忘錄模式來儲存可撤銷操作的的狀態。使用備忘錄可以把複雜的物件內部資訊對其他的物件遮蔽起來。當角色的狀態改變的時候,有可能這個狀態無效,這時候就可以使用暫時儲存起來的備忘錄將狀態復原。
示意圖:
“白箱”備忘錄例項:
定義備忘錄類、記錄類、發起者類
package com.softline.Memento;
public class Memento {
private String state;
public Memento(String state) {
super();
this.state = state;
System.out.println("備忘錄儲存當前的狀態:"+state);
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
package com.softline.Memento;
public class CareTaker {
private Memento memento;
public Memento getMemento(){
return this.memento;
}
public void saveMemento(Memento memento){
this.memento=memento;
}
}
package com.softline.Memento;
public class Originator {
private String state = "0";
public Memento createMemento(){
return new Memento(state);
}
public void restoreMemento(Memento memento){
this.state = memento.getState();
}
public String getState(){
return this.state;
}
public void setState(String state){
this.state = state;
System.out.println("當前狀態:"+this.state);
}
}
定義測試類
package com.softline.Memento;
public class Client {
public static void main(String[] args) {
Originator o = new Originator();
CareTaker c = new CareTaker();
o.setState("on");
c.saveMemento(o.createMemento());
o.setState("off");
o.restoreMemento(c.getMemento());
System.out.println(o.getState());
}
}
windows:
當前狀態:on
備忘錄儲存當前的狀態:on
當前狀態:off
on
“黑箱”備忘錄例項:
定義備忘錄類、記錄類、發起者類
package com.softline.Memento2;
public interface MementoIF {
}
package com.softline.Memento2;
public class Memento implements MementoIF{
private String state;
public Memento(String state) {
super();
this.state = state;
System.out.println("備忘錄儲存當前的狀態:"+state);
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
package com.softline.Memento2;
public class CareTaker {
private MementoIF memento;
public MementoIF getMemento(){
return this.memento;
}
public void saveMemento(MementoIF memento){
this.memento=memento;
}
}
package com.softline.Memento2;
public class Originator {
private String state = "0";
public MementoIF createMemento(){
return new Memento(state);
}
public void restoreMemento(MementoIF memento){
this.setState(((Memento)memento).getState());
}
public String getState(){
return this.state;
}
public void setState(String state){
this.state = state;
System.out.println("當前狀態:"+this.state);
}
}
客戶端
package com.softline.Memento2;
public class Client {
public static void main(String[] args) {
Originator o = new Originator();
CareTaker c = new CareTaker();
o.setState("on");
c.saveMemento(o.createMemento());
o.setState("off");
o.restoreMemento(c.getMemento());
System.out.println(o.getState());
}
}
備忘錄模式與命令模式結合例項:
命令類、備忘錄類、操作類介面,命令類抽象類
package com.softline.MementoAndCommand;
public interface ICommand {
public void execute();
public void undo(IMemento m);
public void redo(IMemento m);
public IMemento createMemento();
}
package com.softline.MementoAndCommand;
public interface IMemento {
}
package com.softline.MementoAndCommand;
public interface IOperationApi {
public int getResult();
public void add(int num);
public void substract(int num);
public IMemento createMemto();
public void setMemento(IMemento memento);
}
package com.softline.MementoAndCommand;
public abstract class AbstractCommand implements ICommand{
protected IOperationApi operation = null;
public void setOperation(IOperationApi operation){
this.operation=operation;
}
@Override
public void execute(){}
@Override
public void undo(IMemento memento){
this.operation.setMemento(memento);
}
@Override
public void redo(IMemento memento){
this.operation.setMemento(memento);
}
@Override
public IMemento createMemento(){
return this.operation.createMemto();
}
}
加法命令、減法命令、操作類實現類
package com.softline.MementoAndCommand;
public class AddCommand extends AbstractCommand {
private int openNum;
public AddCommand(int openNum){
this.openNum=openNum;
}
@Override
public void execute(){
this.operation.add(openNum);
}
}
package com.softline.MementoAndCommand;
public class SubstractCommand extends AbstractCommand{
private int opeNum;
public SubstractCommand(int opeNum){
this.opeNum=opeNum;
}
@Override
public void execute(){
this.operation.substract(opeNum);
}
}
package com.softline.MementoAndCommand;
public class OperationImpl implements IOperationApi {
private int result;
@Override
public int getResult() {
// TODO Auto-generated method stub
return this.result;
}
@Override
public void add(int num) {
// TODO Auto-generated method stub
this.result+=num;
}
@Override
public void substract(int num) {
// TODO Auto-generated method stub
this.result-=num;
}
@Override
public IMemento createMemto() {
// TODO Auto-generated method stub
return new MementoImpl(this.result);
}
@Override
public void setMemento(IMemento memento) {
// TODO Auto-generated method stub
this.result = ((MementoImpl)memento).getResult();
}
private static class MementoImpl implements IMemento{
private int result = 0;
public MementoImpl(int result){
this.result=result;
}
public int getResult(){
return this.result;
}
}
}
計算器類、客戶端
package com.softline.MementoAndCommand;
import java.util.ArrayList;
import java.util.List;
public class Caculator {
private List<ICommand> undoCommands = new ArrayList<ICommand>();
private List<ICommand> redoCommands = new ArrayList<ICommand>();
private List<IMemento[]> undoMementos = new ArrayList<IMemento[]>();
private List<IMemento[]> redoMementos = new ArrayList<IMemento[]>();
private ICommand addCommand;
private ICommand substractCommand;
public void setSubstractCommand(ICommand substractCommand){
this.substractCommand=substractCommand;
}
public void setAddCommand(ICommand addCommand){
this.addCommand=addCommand;
}
public void addPressed(){
IMemento m1 = this.addCommand.createMemento();
this.addCommand.execute();
undoCommands.add(addCommand);
IMemento m2 = this.addCommand.createMemento();
this.undoMementos.add(new IMemento[]{m1,m2});
}
public void substractPressed(){
IMemento m1 = this.substractCommand.createMemento();
this.substractCommand.execute();
undoCommands.add(this.substractCommand);
IMemento m2 = this.substractCommand.createMemento();
this.undoMementos.add(new IMemento[]{m1,m2});
}
public void undoPressed(){
if(undoCommands.size()>0){
ICommand cmd = undoCommands.get(undoCommands.size()-1);
IMemento[] ms = undoMementos.get(undoCommands.size()-1);
cmd.undo(ms[0]);
redoCommands.add(cmd);
redoMementos.add(ms);
undoCommands.remove(cmd);
undoMementos.remove(ms);
}else{
System.out.println("沒有可以撤銷的操作");
}
}
public void redoPressed(){
if(redoCommands.size()>0){
ICommand cmd = redoCommands.get(redoCommands.size()-1);
IMemento[] ms = redoMementos.get(redoCommands.size()-1);
cmd.redo(ms[1]);
undoCommands.add(cmd);
undoMementos.add(ms);
redoCommands.remove(cmd);
redoMementos.remove(ms);
}else{
System.out.println("沒有可以恢復的命令");
}
}
}
package com.softline.MementoAndCommand;
public class Client {
public static void main(String[] args) {
IOperationApi operation = new OperationImpl();
AddCommand addcmd = new AddCommand(5);
SubstractCommand substractCmd = new SubstractCommand(2);
addcmd.setOperation(operation);
substractCmd.setOperation(operation);
Caculator caculator = new Caculator();
caculator.setAddCommand(addcmd);
caculator.setSubstractCommand(substractCmd);
caculator.addPressed();
System.out.println("一次加法運算後的結果"+operation.getResult());
caculator.substractPressed();
System.out.println("一次減法運算後的結果"+operation.getResult());
caculator.undoPressed();
System.out.println("一次撤銷後的結果"+operation.getResult());
caculator.undoPressed();
System.out.println("再一次撤銷後的結果"+operation.getResult());
caculator.redoPressed();
System.out.println("一次恢復後的結果"+operation.getResult());
caculator.redoPressed();
System.out.println("再一次恢復後的結果"+operation.getResult());
}
}
windows:
一次加法運算後的結果5
一次減法運算後的結果3
一次撤銷後的結果5
再一次撤銷後的結果0
一次恢復後的結果5
再一次恢復後的結果3
七、狀態模式
定義:當一個物件的內在狀態改變時允許改變其行為,這個物件看起來像是改變了其類。
使用場景:狀態模式主要解決的是當控制一個物件狀態轉換的條件表示式過於複雜的情況。把狀態的判斷邏輯轉移到表示不同狀態的一系列類當中,可以把複雜的邏輯簡單化。將特定的狀態相關的行為都放入一個物件中,由於所有與狀態相關的程式碼都存在於某個ConcreteState中,所以通過定義新的子類可以很容易的增加新的狀態和轉換。狀態模式通過把各種狀態轉移邏輯分佈到State的子類之間,來減少相互間的依賴。當一個物件的行為取決於他的狀態,並且他必須在執行時刻根據狀態改變它的行為時,就可以考慮使用狀態模式了。
示意圖:
例項:
狀態類介面以及實現類
package com.softline.state;
public interface ITVState {
public void channelUp();
public void channelDown();
public void volumeUp();
public void volumeDown();
}
package com.softline.state;
public class TVOnState implements ITVState {
@Override
public void channelUp() {
// TODO Auto-generated method stub
System.out.println("增加頻道");
}
@Override
public void channelDown() {
// TODO Auto-generated method stub
System.out.println("減少頻道");
}
@Override
public void volumeUp() {
// TODO Auto-generated method stub
System.out.println("增加音量");
}
@Override
public void volumeDown() {
// TODO Auto-generated method stub
System.out.println("減小音量");
}
}
package com.softline.state;
public class TVDownState implements ITVState {
@Override
public void channelUp() {
// TODO Auto-generated method stub
}
@Override
public void channelDown() {
// TODO Auto-generated method stub
}
@Override
public void volumeUp() {
// TODO Auto-generated method stub
}
@Override
public void volumeDown() {
// TODO Auto-generated method stub
}
}
狀態類控制器及客戶端
package com.softline.state;
public class TVController {
private ITVState state;
public void setTVState(ITVState state){
this.state=state;
}
public void powerOn(){
this.setTVState(new TVOnState());
System.out.println("開啟電視");
}
public void powerOff(){
this.setTVState(new TVDownState());
System.out.println("關閉電視");
}
public void channelUp(){
state.channelUp();
}
public void channelDown(){
state.channelDown();
}
public void volumeUp(){
state.volumeUp();
}
public void volumeDown(){
state.volumeDown();
}
}
package com.softline.state;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
TVController control = new TVController();
control.powerOn();
control.channelUp();
control.channelDown();
control.volumeUp();
control.volumeDown();
control.powerOff();
control.channelUp();
}
}
windows:
開啟電視
增加頻道
減少頻道
增加音量
減小音量
關閉電視
七、訪問者模式
定義:表示一個作用與某物件結構中各元素的操作。它使你可以不改變各元素類的前提下定義作用於這些元素的新操作。
使用場景:訪問模式適用於資料結構相對穩定的系統,他把資料結構和作用於結構上的操作之間的耦合解脫開,使得操作集合可以相對自由的演化。訪問者模式的目的是要把處理從資料結構分離出來,如果系統有比較穩定的資料結構,又有易於變化的演算法,使用訪問者模式比較合適。訪問者模式的有點就是增加新的操作很容易,因為增加新的操作就意味著增加一個新的訪問者。
示意圖:
例項:
賬單介面及實現類
package com.softline.visitor;
public interface IBill {
public void accept(IAccountBookView bookView);
}
package com.softline.visitor;
public class IncomeBill implements IBill {
private double amount;
private String item;
public IncomeBill(double amount,String item){
this.amount=amount;
this.item=item;
}
@Override
public void accept(IAccountBookView bookView) {
// TODO Auto-generated method stub
bookView.view(this);
}
public double getAmount(){
return amount;
}
public String getItem(){
return item;
}
}
package com.softline.visitor;
public class ConsumeBill implements IBill {
private double amount;
private String item;
public ConsumeBill(double amount,String item){
this.amount=amount;
this.item=item;
}
@Override
public void accept(IAccountBookView bookView) {
// TODO Auto-generated method stub
bookView.view(this);
}
public double getAmount(){
return amount;
}
public String getItem(){
return item;
}
}
賬單檢視介面和實現類
package com.softline.visitor;
public interface IAccountBookView {
public void view(ConsumeBill bill);
public void view(IncomeBill bill);
}
package com.softline.visitor;
public class Boss implements IAccountBookView {
private double totalIncome;
private double totalConsume;
@Override
public void view(ConsumeBill bill) {
// TODO Auto-generated method stub
totalConsume+=bill.getAmount();
}
@Override
public void view(IncomeBill bill) {
// TODO Auto-generated method stub
totalIncome+=bill.getAmount();
}
public double getTotalIncome(){
System.out.println("老闆檢視一共收入多少,數目是:"+totalIncome);
return totalIncome;
}
public double getTotalConsume(){
System.out.println("老闆檢視一共花費多少,數目是:"+totalConsume);
return totalConsume;
}
}
package com.softline.visitor;
public class CPA implements IAccountBookView {
@Override
public void view(ConsumeBill bill) {
// TODO Auto-generated method stub
if (bill.getItem().equals("工資")) {
System.out.println("注會檢視賬本時,如果單子的消費目的是發工資,則注會會檢視有沒有交個人所得稅。");
}
}
@Override
public void view(IncomeBill bill) {
// TODO Auto-generated method stub
System.out.println("注會檢視賬本時,只要是收入,注會都要檢視公司交稅了沒。");
}
}
賬單和客戶端
package com.softline.visitor;
import java.util.ArrayList;
import java.util.List;
public class AccountBook {
private List<IBill> billList = new ArrayList<IBill>();
public void addBill(IBill bill){
billList.add(bill);
}
public void show(IAccountBookView viewer){
for(IBill bill:billList){
bill.accept(viewer);
}
}
}
package com.softline.visitor;
public class Client {
public static void main(String[] args) {
AccountBook accountBook = new AccountBook();
//新增兩條收入
accountBook.addBill(new IncomeBill(10000, "賣商品"));
accountBook.addBill(new IncomeBill(12000, "賣廣告位"));
//新增兩條支出
accountBook.addBill(new ConsumeBill(1000, "工資"));
accountBook.addBill(new ConsumeBill(2000, "材料費"));
IAccountBookView boss = new Boss();
IAccountBookView cpa = new CPA();
//兩個訪問者分別訪問賬本
accountBook.show(boss);
accountBook.show(cpa);
((Boss) boss).getTotalConsume();
((Boss) boss).getTotalIncome();
}
}
windows:
注會檢視賬本時,只要是收入,注會都要檢視公司交稅了沒。
注會檢視賬本時,只要是收入,注會都要檢視公司交稅了沒。
注會檢視賬本時,如果單子的消費目的是發工資,則注會會檢視有沒有交個人所得稅。
老闆檢視一共花費多少,數目是:3000.0
老闆檢視一共收入多少,數目是:22000.0
八、中介模式
定義:用一箇中介物件來封裝一系列的物件互動。中介者使得各物件不需要顯示地相互引用,從而使其耦合鬆散,而且可以獨立的改變他們之間的互動。
使用場景:中介模式很容易在系統中應用,也很容易在系統中誤用。當系統出現了‘多對多’互動複雜的物件群時,不要急於使用中介模式,而要先反思你係統在設計上是不是合理。Mediator的出現減少了各個colleage的耦合,使得可以獨立地改變和複用各個Colleague類和Mediator。由於把物件如何協作進行了抽象,將中介作為一個獨立的概念並將其封裝在一個物件中,這樣關注的物件就從各自本身的行為轉移到他們之間的互動上來,也就是站在一個更加巨集觀的角度看待系統。由於ConcreteMediator控制了集中化,於是就把互動的複雜性變為了中介的複雜性,這就使得中介者會變得比任何一個ConcreteColleague都複雜。中介模式一般用於一組定義良好但是複雜的方式進行通訊的場合。以及想定製一個分佈在多個類中的行為,而不像生成太多子類的行為。
示意圖:
例項:
定義抽象類和中介類
package com.softline.mediator;
public abstract class AbstractPerson {
protected AbstractMediator mediator;
protected String name;
public AbstractPerson(AbstractMediator mediator,String name){
this.mediator=mediator;
this.name=name;
}
public void setMediator(AbstractMediator mediator){
this.mediator=mediator;
}
protected abstract void sendMessage(String msg);
protected abstract void getMessage(String msg);
}
package com.softline.mediator;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractMediator {
protected List<AbstractPerson> landlordList = new ArrayList<AbstractPerson>();
protected List<AbstractPerson> renterList = new ArrayList<AbstractPerson>();
public void registerLandlord(AbstractPerson landLord) {
landlordList.add(landLord);
}
public void registerRenter(AbstractPerson renter){
renterList.add(renter);
}
public abstract void operation(AbstractPerson person, String message);
}
定義抽象類實現類和中介類實現類
package com.softline.mediator;
public class LandLord extends AbstractPerson {
public LandLord(AbstractMediator mediator,String name){
super(mediator,name);
}
@Override
protected void sendMessage(String msg) {
// TODO Auto-generated method stub
super.mediator.operation(this, msg);
}
@Override
protected void getMessage(String msg) {
// TODO Auto-generated method stub
System.out.println("房東"+super.name+"收到中介發來的訊息"+msg);
}
}
package com.softline.mediator;
public class Renter extends AbstractPerson {
public Renter(AbstractMediator mediator,String name){
super(mediator,name);
}
@Override
protected void sendMessage(String msg) {
// TODO Auto-generated method stub
super.mediator.operation(this, msg);
}
@Override
protected void getMessage(String msg) {
// TODO Auto-generated method stub
System.out.println("求租者"+super.name+"收到中介發來的訊息"+msg);
}
}
package com.softline.mediator;
public class HouseMediator extends AbstractMediator {
@Override
public void operation(AbstractPerson person, String message) {
// TODO Auto-generated method stub
// 如果是租房者,就把租房者的需求資訊傳遞給註冊了的房東們
if (person instanceof Renter) {
for (AbstractPerson landlord : landlordList) {
landlord.getMessage(message);
}
} else if (person instanceof LandLord) {
// 如果是房東,就把房東的出租訊息傳遞給註冊了的求租者
for (AbstractPerson renter : renterList) {
renter.getMessage(message);
}
}
}
}
客戶端
package com.softline.mediator;
public class Client {
public static void main(String[] args) {
AbstractMediator mediator = new HouseMediator();
AbstractPerson landlordA, landlordB, renter;
landlordA = new LandLord(mediator, "a");
landlordB = new LandLord(mediator, "b");
renter = new Renter(mediator, "小呂");
mediator.registerLandlord(landlordA);
mediator.registerLandlord(landlordB);
mediator.registerRenter(renter);
renter.sendMessage("想在四惠東附近租套一居室,加個1500");
landlordA.sendMessage("在四惠東附近有一套兩居室要出租,租金3000,聯絡電話0101010101001");
}
}
windows:
房東房東a收到中介發來的訊息想在四惠東附近租套一居室,加個1500
房東房東b收到中介發來的訊息想在四惠東附近租套一居室,加個1500
求租者小呂收到中介發來的訊息在四惠東附近有一套兩居室要出租,租金3000,聯絡電話0101010101001
九、直譯器模式
定義:給定一個語言,定義它的文法的一種表示,並定義一個直譯器,這個直譯器使用該表示來解釋語言中的句子。
使用場景:如果一種特定問題發生的頻率足夠高,那麼可能就值得將該問題的各例項表述為一個簡單語言中的句子。這樣就可以構建一個直譯器,該直譯器通過解釋這些句子來解決該問題。當一個語言需要解釋執行並且你可將該語言中的句子表示為抽象語法樹時,可使用直譯器模式。直譯器模式為文法中的每一條規則至少定義了一個類,因此包含許多規則的文法可能難以管理和維護。建議當文法非常複雜時,使用其他的技術如語法分析程式或編譯器生成器來處理。
示意圖:
例項:
定義介面、抽象類及實現類
package com.softline.interpreter;
public interface INode {
public int interpret();
}
package com.softline.interpreter;
public abstract class AbstractSysbolNode implements INode {
protected INode left;
protected INode right;
public AbstractSysbolNode(INode left,INode right){
this.left=left;
this.right=right;
}
}
package com.softline.interpreter;
public class ValueNode implements INode {
private int value;
public ValueNode(int value){
this.value=value;
}
@Override
public int interpret() {
// TODO Auto-generated method stub
return this.value;
}
}
package com.softline.interpreter;
public class ModNode extends AbstractSysbolNode {
public ModNode(INode left, INode right) {
super(left, right);
// TODO Auto-generated constructor stub
}
@Override
public int interpret() {
// TODO Auto-generated method stub
return super.left.interpret() % super.right.interpret();
}
}
package com.softline.interpreter;
public class MulNode extends AbstractSysbolNode {
public MulNode(INode left, INode right) {
super(left, right);
// TODO Auto-generated constructor stub
}
@Override
public int interpret() {
// TODO Auto-generated method stub
return left.interpret()*right.interpret();
}
}
定義計算器以及客戶端
package com.softline.interpreter;
import java.util.Stack;
public class Calculator {
private String statement;
private INode node;
public void build(String statement){
INode left=null,right=null;
Stack stack=new Stack();
String[] statementArr=statement.split(" ");
for(int i=0;i<statementArr.length;i++){
if(statementArr[i].equalsIgnoreCase("*")){
left=(INode)stack.pop();
int val=Integer.parseInt(statementArr[++i]);
right=new ValueNode(val);
stack.push(new MulNode(left,right));
}
else if(statementArr[i].equalsIgnoreCase("/")){
left=(INode)stack.pop();
int val=Integer.parseInt(statementArr[++i]);
right=new ValueNode(val);
stack.push(new DivNode(left,right));
}
else if(statementArr[i].equalsIgnoreCase("%")){
left=(INode)stack.pop();
int val=Integer.parseInt(statementArr[++i]);
right=new ValueNode(val);
stack.push(new ModNode(left,right));
}
else{
stack.push(new ValueNode(Integer.parseInt(statementArr[i])));
}
}
this.node=(INode)stack.pop();
}
public int compute(){
return node.interpret();
}
}
package com.softline.interpreter;
public class Client {
public static void main(String[] args) {
String statement = "3 * 2 * 4 / 6 % 5";
Calculator calculator = new Calculator();
calculator.build(statement);
int result = calculator.compute();
System.out.println(statement + " = " + result);
}
}
windows:
3 * 2 * 4 / 6 % 5 = 4