解釋器模式(Interpreter Pattern)提供了評估語言的語法或表達式的方式,它屬於行爲型模式。這種模式實現了一個表達式接口,該接口解釋一個特定的上下文。這種模式被用在 SQL 解析、符號處理引擎等。html
意圖:給定一個語言,定義它的文法表示,並定義一個解釋器,這個解釋器使用該標識來解釋語言中的句子。前端
主要解決:對於一些固定文法構建一個解釋句子的解釋器。java
什麼時候使用:若是一種特定類型的問題發生的頻率足夠高,那麼可能就值得將該問題的各個實例表述爲一個簡單語言中的句子。這樣就能夠構建一個解釋器,該解釋器經過解釋這些句子來解決該問題。程序員
如何解決:構建語法樹,定義終結符與非終結符。web
關鍵代碼:構建環境類,包含解釋器以外的一些全局信息,通常是 HashMap。算法
應用實例:編譯器、運算表達式計算。spring
優勢: 一、可擴展性比較好,靈活。 二、增長了新的解釋表達式的方式。 三、易於實現簡單文法。數據庫
缺點: 一、可利用場景比較少。 二、對於複雜的文法比較難維護。 三、解釋器模式會引發類膨脹。 四、解釋器模式採用遞歸調用方法。express
使用場景: 一、能夠將一個須要解釋執行的語言中的句子表示爲一個抽象語法樹。 二、一些重複出現的問題能夠用一種簡單的語言來進行表達。 三、一個簡單語法須要解釋的場景。編程
注意事項:可利用場景比較少,JAVA 中若是碰到能夠用 expression4J 代替。
咱們將建立一個接口 Expression 和實現了 Expression 接口的實體類。定義做爲上下文中主要解釋器的 TerminalExpression 類。其餘的類 OrExpression、AndExpression 用於建立組合式表達式。
InterpreterPatternDemo,咱們的演示類使用 Expression 類建立規則和演示表達式的解析。
步驟 1
建立一個表達式接口。
Expression.java
public interface Expression {
public boolean interpret(String context);
}
複製代碼
步驟 2
建立實現了上述接口的實體類。
TerminalExpression.java
public class TerminalExpression implements Expression {
private String data;
public TerminalExpression(String data){
this.data = data;
}
@Override
public boolean interpret(String context) {
if(context.contains(data)){
return true;
}
return false;
}
}
複製代碼
OrExpression.java
public class OrExpression implements Expression {
private Expression expr1 = null;
private Expression expr2 = null;
public OrExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(String context) {
return expr1.interpret(context) || expr2.interpret(context);
}
}
複製代碼
AndExpression.java
public class AndExpression implements Expression {
private Expression expr1 = null;
private Expression expr2 = null;
public AndExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(String context) {
return expr1.interpret(context) && expr2.interpret(context);
}
}
複製代碼
步驟 3
InterpreterPatternDemo 使用 Expression 類來建立規則,並解析它們。
InterpreterPatternDemo.java
public class InterpreterPatternDemo {
//規則:Robert 和 John 是男性
public static Expression getMaleExpression(){
Expression robert = new TerminalExpression("Robert");
Expression john = new TerminalExpression("John");
return new OrExpression(robert, john);
}
//規則:Julie 是一個已婚的女性
public static Expression getMarriedWomanExpression(){
Expression julie = new TerminalExpression("Julie");
Expression married = new TerminalExpression("Married");
return new AndExpression(julie, married);
}
public static void main(String[] args) {
Expression isMale = getMaleExpression();
Expression isMarriedWoman = getMarriedWomanExpression();
System.out.println("John is male? " + isMale.interpret("John"));
System.out.println("Julie is a married women? "
+ isMarriedWoman.interpret("Married Julie"));
}
}
複製代碼
步驟 4
執行程序,輸出結果:
John is male? true
Julie is a married women? true
複製代碼
迭代器模式(Iterator Pattern)是 Java 和 .Net 編程環境中很是經常使用的設計模式。這種模式用於順序訪問集合對象的元素,不須要知道集合對象的底層表示。
迭代器模式屬於行爲型模式。
意圖:提供一種方法順序訪問一個聚合對象中各個元素, 而又無須暴露該對象的內部表示。
主要解決:不一樣的方式來遍歷整個整合對象。
什麼時候使用:遍歷一個聚合對象。
如何解決:把在元素之間遊走的責任交給迭代器,而不是聚合對象。
關鍵代碼:定義接口:hasNext, next。
應用實例:JAVA 中的 iterator。
優勢: 一、它支持以不一樣的方式遍歷一個聚合對象。 二、迭代器簡化了聚合類。 三、在同一個聚合上能夠有多個遍歷。 四、在迭代器模式中,增長新的聚合類和迭代器類都很方便,無須修改原有代碼。
缺點:因爲迭代器模式將存儲數據和遍歷數據的職責分離,增長新的聚合類須要對應增長新的迭代器類,類的個數成對增長,這在必定程度上增長了系統的複雜性。
使用場景: 一、訪問一個聚合對象的內容而無須暴露它的內部表示。 二、須要爲聚合對象提供多種遍歷方式。 三、爲遍歷不一樣的聚合結構提供一個統一的接口。
注意事項:迭代器模式就是分離了集合對象的遍歷行爲,抽象出一個迭代器類來負責,這樣既能夠作到不暴露集合的內部結構,又可以讓外部代碼透明地訪問集合內部的數據。
咱們將建立一個敘述導航方法的 Iterator 接口和一個返回迭代器的 Container 接口。實現了 Container 接口的實體類將負責實現 Iterator 接口。
IteratorPatternDemo,咱們的演示類使用實體類 NamesRepository 來打印 NamesRepository 中存儲爲集合的 Names。
步驟 1
建立接口:
Iterator.java
public interface Iterator {
public boolean hasNext();
public Object next();
}
Container.java
public interface Container {
public Iterator getIterator();
}
複製代碼
步驟 2
建立實現了 Container 接口的實體類。該類有實現了 Iterator 接口的內部類 NameIterator。
NameRepository.java
public class NameRepository implements Container {
public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};
@Override
public Iterator getIterator() {
return new NameIterator();
}
private class NameIterator implements Iterator {
int index;
@Override
public boolean hasNext() {
if(index < names.length){
return true;
}
return false;
}
@Override
public Object next() {
if(this.hasNext()){
return names[index++];
}
return null;
}
}
}
複製代碼
步驟 3
使用 NameRepository 來獲取迭代器,並打印名字。
IteratorPatternDemo.java
public class IteratorPatternDemo {
public static void main(String[] args) {
NameRepository namesRepository = new NameRepository();
for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){
String name = (String)iter.next();
System.out.println("Name : " + name);
}
}
}
複製代碼
步驟 4
執行程序,輸出結果:
Name : Robert
Name : John
Name : Julie
Name : Lora
複製代碼
中介者模式(Mediator Pattern)是用來下降多個對象和類之間的通訊複雜性。這種模式提供了一箇中介類,該類一般處理不一樣類之間的通訊,並支持鬆耦合,使代碼易於維護。中介者模式屬於行爲型模式。
意圖:用一箇中介對象來封裝一系列的對象交互,中介者使各對象不須要顯式地相互引用,從而使其耦合鬆散,並且能夠獨立地改變它們之間的交互。
主要解決:對象與對象之間存在大量的關聯關係,這樣勢必會致使系統的結構變得很複雜,同時若一個對象發生改變,咱們也須要跟蹤與之相關聯的對象,同時作出相應的處理。
什麼時候使用:多個類相互耦合,造成了網狀結構。
如何解決:將上述網狀結構分離爲星型結構。
關鍵代碼:對象 Colleague 之間的通訊封裝到一個類中單獨處理。
應用實例: 一、中國加入 WTO 以前是各個國家相互貿易,結構複雜,如今是各個國家經過 WTO 來互相貿易。 二、機場調度系統。 三、MVC 框架,其中C(控制器)就是 M(模型)和 V(視圖)的中介者。
優勢: 一、下降了類的複雜度,將一對多轉化成了一對一。 二、各個類之間的解耦。 三、符合迪米特原則。
缺點:中介者會龐大,變得複雜難以維護。
使用場景: 一、系統中對象之間存在比較複雜的引用關係,致使它們之間的依賴關係結構混亂並且難以複用該對象。 二、想經過一箇中間類來封裝多個類中的行爲,而又不想生成太多的子類。
注意事項:不該當在職責混亂的時候使用。
咱們經過聊天室實例來演示中介者模式。實例中,多個用戶能夠向聊天室發送消息,聊天室向全部的用戶顯示消息。咱們將建立兩個類 ChatRoom 和 User。User 對象使用 ChatRoom 方法來分享他們的消息。
MediatorPatternDemo,咱們的演示類使用 User 對象來顯示他們之間的通訊。
步驟 1
建立中介類。
ChatRoom.java
import java.util.Date;
public class ChatRoom {
public static void showMessage(User user, String message){
System.out.println(new Date().toString()
+ " [" + user.getName() +"] : " + message);
}
}
複製代碼
步驟 2
建立 user 類。
User.java
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String name){
this.name = name;
}
public void sendMessage(String message){
ChatRoom.showMessage(this,message);
}
}
複製代碼
步驟 3
使用 User 對象來顯示他們之間的通訊。
MediatorPatternDemo.java
public class MediatorPatternDemo {
public static void main(String[] args) {
User robert = new User("Robert");
User john = new User("John");
robert.sendMessage("Hi! John!");
john.sendMessage("Hello! Robert!");
}
}
複製代碼
步驟 4
執行程序,輸出結果:
Thu Jan 31 16:05:46 IST 2013 [Robert] : Hi! John!
Thu Jan 31 16:05:46 IST 2013 [John] : Hello! Robert!
複製代碼
原文更多例子:www.runoob.com/design-patt…
備忘錄模式(Memento Pattern)保存一個對象的某個狀態,以便在適當的時候恢復對象。備忘錄模式屬於行爲型模式。
意圖:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。
主要解決:所謂備忘錄模式就是在不破壞封裝的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態,這樣能夠在之後將對象恢復到原先保存的狀態。
什麼時候使用:不少時候咱們老是須要記錄一個對象的內部狀態,這樣作的目的就是爲了容許用戶取消不肯定或者錯誤的操做,可以恢復到他原先的狀態,使得他有"後悔藥"可吃。
如何解決:經過一個備忘錄類專門存儲對象狀態。
關鍵代碼:客戶不與備忘錄類耦合,與備忘錄管理類耦合。
應用實例: 一、後悔藥。 二、打遊戲時的存檔。 三、Windows 裏的 ctri + z。 四、IE 中的後退。 四、數據庫的事務管理。
優勢: 一、給用戶提供了一種能夠恢復狀態的機制,可使用戶可以比較方便地回到某個歷史的狀態。 二、實現了信息的封裝,使得用戶不須要關心狀態的保存細節。
缺點:消耗資源。若是類的成員變量過多,勢必會佔用比較大的資源,並且每一次保存都會消耗必定的內存。
使用場景: 一、須要保存/恢復數據的相關狀態場景。 二、提供一個可回滾的操做。
注意事項: 一、爲了符合迪米特原則,還要增長一個管理備忘錄的類。 二、爲了節約內存,可以使用原型模式+備忘錄模式。
備忘錄模式使用三個類 Memento、Originator 和 CareTaker。Memento 包含了要被恢復的對象的狀態。Originator 建立並在 Memento 對象中存儲狀態。Caretaker 對象負責從 Memento 中恢復對象的狀態。
MementoPatternDemo,咱們的演示類使用 CareTaker 和 Originator 對象來顯示對象的狀態恢復。
步驟 1
建立 Memento 類。
Memento.java
public class Memento {
private String state;
public Memento(String state){
this.state = state;
}
public String getState(){
return state;
}
}
複製代碼
步驟 2
建立 Originator 類。
Originator.java
public class Originator {
private String state;
public void setState(String state){
this.state = state;
}
public String getState(){
return state;
}
public Memento saveStateToMemento(){
return new Memento(state);
}
public void getStateFromMemento(Memento Memento){
state = Memento.getState();
}
}
複製代碼
步驟 3
建立 CareTaker 類。
CareTaker.java
import java.util.ArrayList;
import java.util.List;
public class CareTaker {
private List<Memento> mementoList = new ArrayList<Memento>();
public void add(Memento state){
mementoList.add(state);
}
public Memento get(int index){
return mementoList.get(index);
}
}
複製代碼
步驟 4
使用 CareTaker 和 Originator 對象。
MementoPatternDemo.java
public class MementoPatternDemo {
public static void main(String[] args) {
Originator originator = new Originator();
CareTaker careTaker = new CareTaker();
originator.setState("State #1");
originator.setState("State #2");
careTaker.add(originator.saveStateToMemento());
originator.setState("State #3");
careTaker.add(originator.saveStateToMemento());
originator.setState("State #4");
System.out.println("Current State: " + originator.getState());
originator.getStateFromMemento(careTaker.get(0));
System.out.println("First saved State: " + originator.getState());
originator.getStateFromMemento(careTaker.get(1));
System.out.println("Second saved State: " + originator.getState());
}
}
複製代碼
步驟 5
驗證輸出。
Current State: State #4
First saved State: State #2
Second saved State: State #3
複製代碼
當對象間存在一對多關係時,則使用觀察者模式(Observer Pattern)。好比,當一個對象被修改時,則會自動通知它的依賴對象。觀察者模式屬於行爲型模式。
意圖:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並被自動更新。
主要解決:一個對象狀態改變給其餘對象通知的問題,並且要考慮到易用和低耦合,保證高度的協做。
什麼時候使用:一個對象(目標對象)的狀態發生改變,全部的依賴對象(觀察者對象)都將獲得通知,進行廣播通知。
如何解決:使用面向對象技術,能夠將這種依賴關係弱化。
關鍵代碼:在抽象類裏有一個 ArrayList 存放觀察者們。
應用實例: 一、拍賣的時候,拍賣師觀察最高標價,而後通知給其餘競價者競價。 二、西遊記裏面悟空請求菩薩降服紅孩兒,菩薩灑了一地水招來一個老烏龜,這個烏龜就是觀察者,他觀察菩薩灑水這個動做。
優勢: 一、觀察者和被觀察者是抽象耦合的。 二、創建一套觸發機制。
缺點: 一、若是一個被觀察者對象有不少的直接和間接的觀察者的話,將全部的觀察者都通知到會花費不少時間。 二、若是在觀察者和觀察目標之間有循環依賴的話,觀察目標會觸發它們之間進行循環調用,可能致使系統崩潰。 三、觀察者模式沒有相應的機制讓觀察者知道所觀察的目標對象是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。
使用場景:
一個抽象模型有兩個方面,其中一個方面依賴於另外一個方面。將這些方面封裝在獨立的對象中使它們能夠各自獨立地改變和複用。 一個對象的改變將致使其餘一個或多個對象也發生改變,而不知道具體有多少對象將發生改變,能夠下降對象之間的耦合度。 一個對象必須通知其餘對象,而並不知道這些對象是誰。 須要在系統中建立一個觸發鏈,A對象的行爲將影響B對象,B對象的行爲將影響C對象……,可使用觀察者模式建立一種鏈式觸發機制。 注意事項: 一、JAVA 中已經有了對觀察者模式的支持類。 二、避免循環引用。 三、若是順序執行,某一觀察者錯誤會致使系統卡殼,通常採用異步方式。
觀察者模式使用三個類 Subject、Observer 和 Client。Subject 對象帶有綁定觀察者到 Client 對象和從 Client 對象解綁觀察者的方法。咱們建立 Subject 類、Observer 抽象類和擴展了抽象類 Observer 的實體類。
ObserverPatternDemo,咱們的演示類使用 Subject 和實體類對象來演示觀察者模式。
步驟 1
建立 Subject 類。
Subject.java
import java.util.ArrayList;
import java.util.List;
public class Subject {
private List<Observer> observers
= new ArrayList<Observer>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
public void attach(Observer observer){
observers.add(observer);
}
public void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
}
複製代碼
步驟 2
建立 Observer 類。
Observer.java
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
複製代碼
步驟 3
建立實體觀察者類。
BinaryObserver.java
public class BinaryObserver extends Observer{
public BinaryObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Binary String: "
+ Integer.toBinaryString( subject.getState() ) );
}
}
複製代碼
OctalObserver.java
public class OctalObserver extends Observer{
public OctalObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Octal String: "
+ Integer.toOctalString( subject.getState() ) );
}
}
複製代碼
HexaObserver.java
public class HexaObserver extends Observer{
public HexaObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Hex String: "
+ Integer.toHexString( subject.getState() ).toUpperCase() );
}
}
複製代碼
步驟 4
使用 Subject 和實體觀察者對象。
ObserverPatternDemo.java
public class ObserverPatternDemo {
public static void main(String[] args) {
Subject subject = new Subject();
new HexaObserver(subject);
new OctalObserver(subject);
new BinaryObserver(subject);
System.out.println("First state change: 15");
subject.setState(15);
System.out.println("Second state change: 10");
subject.setState(10);
}
}
複製代碼
步驟 5 執行程序,輸出結果:
First state change: 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change: 10
Hex String: A
Octal String: 12
Binary String: 1010
複製代碼
在狀態模式(State Pattern)中,類的行爲是基於它的狀態改變的。這種類型的設計模式屬於行爲型模式。
在狀態模式中,咱們建立表示各類狀態的對象和一個行爲隨着狀態對象改變而改變的 context 對象。
意圖:容許對象在內部狀態發生改變時改變它的行爲,對象看起來好像修改了它的類。
主要解決:對象的行爲依賴於它的狀態(屬性),而且能夠根據它的狀態改變而改變它的相關行爲。
什麼時候使用:代碼中包含大量與對象狀態有關的條件語句。
如何解決:將各類具體的狀態類抽象出來。
關鍵代碼:一般命令模式的接口中只有一個方法。而狀態模式的接口中有一個或者多個方法。並且,狀態模式的實現類的方法,通常返回值,或者是改變實例變量的值。也就是說,狀態模式通常和對象的狀態有關。實現類的方法有不一樣的功能,覆蓋接口中的方法。狀態模式和命令模式同樣,也能夠用於消除 if...else 等條件選擇語句。
應用實例: 一、打籃球的時候運動員能夠有正常狀態、不正常狀態和超常狀態。 二、曾侯乙編鐘中,'鍾是抽象接口','鍾A'等是具體狀態,'曾侯乙編鐘'是具體環境(Context)。
優勢: 一、封裝了轉換規則。 二、枚舉可能的狀態,在枚舉狀態以前須要肯定狀態種類。 三、將全部與某個狀態有關的行爲放到一個類中,而且能夠方便地增長新的狀態,只須要改變對象狀態便可改變對象的行爲。 四、容許狀態轉換邏輯與狀態對象合成一體,而不是某一個巨大的條件語句塊。 五、可讓多個環境對象共享一個狀態對象,從而減小系統中對象的個數。
缺點: 一、狀態模式的使用必然會增長系統類和對象的個數。 二、狀態模式的結構與實現都較爲複雜,若是使用不當將致使程序結構和代碼的混亂。 三、狀態模式對"開閉原則"的支持並不太好,對於能夠切換狀態的狀態模式,增長新的狀態類須要修改那些負責狀態轉換的源代碼,不然沒法切換到新增狀態,並且修改某個狀態類的行爲也需修改對應類的源代碼。
使用場景: 一、行爲隨狀態改變而改變的場景。 二、條件、分支語句的代替者。
注意事項:在行爲受狀態約束的時候使用狀態模式,並且狀態不超過 5 個。
咱們將建立一個 State 接口和實現了 State 接口的實體狀態類。Context 是一個帶有某個狀態的類。
StatePatternDemo,咱們的演示類使用 Context 和狀態對象來演示 Context 在狀態改變時的行爲變化。
步驟 1
建立一個接口。
State.java
public interface State {
public void doAction(Context context);
}
複製代碼
步驟 2
建立實現接口的實體類。
StartState.java
public class StartState implements State {
public void doAction(Context context) {
System.out.println("Player is in start state");
context.setState(this);
}
public String toString(){
return "Start State";
}
}
複製代碼
StopState.java
public class StopState implements State {
public void doAction(Context context) {
System.out.println("Player is in stop state");
context.setState(this);
}
public String toString(){
return "Stop State";
}
}
複製代碼
步驟 3 建立 Context 類。
Context.java
public class Context {
private State state;
public Context(){
state = null;
}
public void setState(State state){
this.state = state;
}
public State getState(){
return state;
}
}
複製代碼
步驟 4
使用 Context 來查看當狀態 State 改變時的行爲變化。
StatePatternDemo.java
public class StatePatternDemo {
public static void main(String[] args) {
Context context = new Context();
StartState startState = new StartState();
startState.doAction(context);
System.out.println(context.getState().toString());
StopState stopState = new StopState();
stopState.doAction(context);
System.out.println(context.getState().toString());
}
}
複製代碼
步驟 5
執行程序,輸出結果:
Player is in start state
Start State
Player is in stop state
Stop State
複製代碼
在空對象模式(Null Object Pattern)中,一個空對象取代 NULL 對象實例的檢查。Null 對象不是檢查空值,而是反應一個不作任何動做的關係。這樣的 Null 對象也能夠在數據不可用的時候提供默認的行爲。
在空對象模式中,咱們建立一個指定各類要執行的操做的抽象類和擴展該類的實體類,還建立一個未對該類作任何實現的空對象類,該空對象類將無縫地使用在須要檢查空值的地方。
咱們將建立一個定義操做(在這裏,是客戶的名稱)的 AbstractCustomer 抽象類,和擴展了 AbstractCustomer 類的實體類。工廠類 CustomerFactory 基於客戶傳遞的名字來返回 RealCustomer 或 NullCustomer 對象。
NullPatternDemo,咱們的演示類使用 CustomerFactory 來演示空對象模式的用法。
步驟 1
建立一個抽象類。
AbstractCustomer.java
public abstract class AbstractCustomer {
protected String name;
public abstract boolean isNil();
public abstract String getName();
}
複製代碼
步驟 2
建立擴展了上述類的實體類。
RealCustomer.java
public class RealCustomer extends AbstractCustomer {
public RealCustomer(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public boolean isNil() {
return false;
}
}
複製代碼
NullCustomer.java
public class NullCustomer extends AbstractCustomer {
@Override
public String getName() {
return "Not Available in Customer Database";
}
@Override
public boolean isNil() {
return true;
}
}
複製代碼
步驟 3
建立 CustomerFactory 類。
CustomerFactory.java
public class CustomerFactory {
public static final String[] names = {"Rob", "Joe", "Julie"};
public static AbstractCustomer getCustomer(String name){
for (int i = 0; i < names.length; i++) {
if (names[i].equalsIgnoreCase(name)){
return new RealCustomer(name);
}
}
return new NullCustomer();
}
}
複製代碼
步驟 4
使用 CustomerFactory,基於客戶傳遞的名字,來獲取 RealCustomer 或 NullCustomer 對象。
NullPatternDemo.java
public class NullPatternDemo {
public static void main(String[] args) {
AbstractCustomer customer1 = CustomerFactory.getCustomer("Rob");
AbstractCustomer customer2 = CustomerFactory.getCustomer("Bob");
AbstractCustomer customer3 = CustomerFactory.getCustomer("Julie");
AbstractCustomer customer4 = CustomerFactory.getCustomer("Laura");
System.out.println("Customers");
System.out.println(customer1.getName());
System.out.println(customer2.getName());
System.out.println(customer3.getName());
System.out.println(customer4.getName());
}
}
複製代碼
步驟 5
執行程序,輸出結果:
Customers
Rob
Not Available in Customer Database
Julie
Not Available in Customer Database
複製代碼
在策略模式(Strategy Pattern)中,一個類的行爲或其算法能夠在運行時更改。這種類型的設計模式屬於行爲型模式。
在策略模式中,咱們建立表示各類策略的對象和一個行爲隨着策略對象改變而改變的 context 對象。策略對象改變 context 對象的執行算法。
意圖:定義一系列的算法,把它們一個個封裝起來, 而且使它們可相互替換。
主要解決:在有多種算法類似的狀況下,使用 if...else 所帶來的複雜和難以維護。
什麼時候使用:一個系統有許多許多類,而區分它們的只是他們直接的行爲。
如何解決:將這些算法封裝成一個一個的類,任意地替換。
關鍵代碼:實現同一個接口。
應用實例: 一、諸葛亮的錦囊妙計,每個錦囊就是一個策略。 二、旅行的出遊方式,選擇騎自行車、坐汽車,每一種旅行方式都是一個策略。 三、JAVA AWT 中的 LayoutManager。
優勢: 一、算法能夠自由切換。 二、避免使用多重條件判斷。 三、擴展性良好。
缺點: 一、策略類會增多。 二、全部策略類都須要對外暴露。
使用場景: 一、若是在一個系統裏面有許多類,它們之間的區別僅在於它們的行爲,那麼使用策略模式能夠動態地讓一個對象在許多行爲中選擇一種行爲。 二、一個系統須要動態地在幾種算法中選擇一種。 三、若是一個對象有不少的行爲,若是不用恰當的模式,這些行爲就只好使用多重的條件選擇語句來實現。
注意事項:若是一個系統的策略多於四個,就須要考慮使用混合模式,解決策略類膨脹的問題。
咱們將建立一個定義活動的 Strategy 接口和實現了 Strategy 接口的實體策略類。Context 是一個使用了某種策略的類。
StrategyPatternDemo,咱們的演示類使用 Context 和策略對象來演示 Context 在它所配置或使用的策略改變時的行爲變化。
步驟 1
建立一個接口。
Strategy.java
public interface Strategy {
public int doOperation(int num1, int num2);
}
複製代碼
步驟 2
建立實現接口的實體類。
OperationAdd.java
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
複製代碼
OperationSubstract.java
public class OperationSubstract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
複製代碼
OperationMultiply.java
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
複製代碼
步驟 3
建立 Context 類。
Context.java
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
複製代碼
步驟 4
使用 Context 來查看當它改變策略 Strategy 時的行爲變化。
StrategyPatternDemo.java
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubstract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
複製代碼
步驟 5
執行程序,輸出結果:
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
複製代碼
狀態模式的類圖和策略模式相似,而且都是可以動態改變對象的行爲。可是狀態模式是經過狀態轉移來改變 Context 所組合的 State 對象,而策略模式是經過 Context 自己的決策來改變組合的 Strategy 對象。所謂的狀態轉移,是指 Context 在運行過程當中因爲一些條件發生改變而使得 State 對象發生改變,注意必需要是在運行過程當中。
狀態模式主要是用來解決狀態轉移的問題,當狀態發生轉移了,那麼 Context 對象就會改變它的行爲;而策略模式主要是用來封裝一組能夠互相替代的算法族,而且能夠根據須要動態地去替換 Context 使用的算法。
在模板模式(Template Pattern)中,一個抽象類公開定義了執行它的方法的方式/模板。它的子類能夠按須要重寫方法實現,但調用將以抽象類中定義的方式進行。這種類型的設計模式屬於行爲型模式。
意圖:定義一個操做中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。
主要解決:一些方法通用,卻在每個子類都從新寫了這一方法。
什麼時候使用:有一些通用的方法。
如何解決:將這些通用算法抽象出來。
關鍵代碼:在抽象類實現,其餘步驟在子類實現。
應用實例: 一、在造房子的時候,地基、走線、水管都同樣,只有在建築的後期纔有加壁櫥加柵欄等差別。 二、西遊記裏面菩薩定好的 81 難,這就是一個頂層的邏輯骨架。 三、spring 中對 Hibernate 的支持,將一些已經定好的方法封裝起來,好比開啓事務、獲取 Session、關閉 Session 等,程序員不重複寫那些已經規範好的代碼,直接丟一個實體就能夠保存。
優勢: 一、封裝不變部分,擴展可變部分。 二、提取公共代碼,便於維護。 三、行爲由父類控制,子類實現。
缺點:每個不一樣的實現都須要一個子類來實現,致使類的個數增長,使得系統更加龐大。
使用場景: 一、有多個子類共有的方法,且邏輯相同。 二、重要的、複雜的方法,能夠考慮做爲模板方法。
注意事項:爲防止惡意操做,通常模板方法都加上 final 關鍵詞。
咱們將建立一個定義操做的 Game 抽象類,其中,模板方法設置爲 final,這樣它就不會被重寫。Cricket 和 Football 是擴展了 Game 的實體類,它們重寫了抽象類的方法。
TemplatePatternDemo,咱們的演示類使用 Game 來演示模板模式的用法。
步驟 1
建立一個抽象類,它的模板方法被設置爲 final。
Game.java
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//模板
public final void play(){
//初始化遊戲
initialize();
//開始遊戲
startPlay();
//結束遊戲
endPlay();
}
}
複製代碼
步驟 2
建立擴展了上述類的實體類。
Cricket.java
public class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
複製代碼
Football.java
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
複製代碼
步驟 3
使用 Game 的模板方法 play() 來演示遊戲的定義方式。
TemplatePatternDemo.java
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}
複製代碼
步驟 4
執行程序,輸出結果:
Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!
Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!
複製代碼
在訪問者模式(Visitor Pattern)中,咱們使用了一個訪問者類,它改變了元素類的執行算法。經過這種方式,元素的執行算法能夠隨着訪問者改變而改變。這種類型的設計模式屬於行爲型模式。根據模式,元素對象已接受訪問者對象,這樣訪問者對象就能夠處理元素對象上的操做。
意圖:主要將數據結構與數據操做分離。
主要解決:穩定的數據結構和易變的操做耦合問題。
什麼時候使用:須要對一個對象結構中的對象進行不少不一樣的而且不相關的操做,而須要避免讓這些操做"污染"這些對象的類,使用訪問者模式將這些封裝到類中。
如何解決:在被訪問的類裏面加一個對外提供接待訪問者的接口。
關鍵代碼:在數據基礎類裏面有一個方法接受訪問者,將自身引用傳入訪問者。
應用實例:您在朋友家作客,您是訪問者,朋友接受您的訪問,您經過朋友的描述,而後對朋友的描述作出一個判斷,這就是訪問者模式。
優勢: 一、符合單一職責原則。 二、優秀的擴展性。 三、靈活性。
缺點: 一、具體元素對訪問者公佈細節,違反了迪米特原則。 二、具體元素變動比較困難。 三、違反了依賴倒置原則,依賴了具體類,沒有依賴抽象。
使用場景: 一、對象結構中對象對應的類不多改變,但常常須要在此對象結構上定義新的操做。 二、須要對一個對象結構中的對象進行不少不一樣的而且不相關的操做,而須要避免讓這些操做"污染"這些對象的類,也不但願在增長新操做時修改這些類。
注意事項:訪問者能夠對功能進行統一,能夠作報表、UI、攔截器與過濾器。
咱們將建立一個定義接受操做的 ComputerPart 接口。Keyboard、Mouse、Monitor 和 Computer 是實現了 ComputerPart 接口的實體類。咱們將定義另外一個接口 ComputerPartVisitor,它定義了訪問者類的操做。Computer 使用實體訪問者來執行相應的動做。
VisitorPatternDemo,咱們的演示類使用 Computer、ComputerPartVisitor 類來演示訪問者模式的用法。
步驟 1
定義一個表示元素的接口。
ComputerPart.java
public interface ComputerPart {
public void accept(ComputerPartVisitor computerPartVisitor);
}
複製代碼
步驟 2
建立擴展了上述類的實體類。
Keyboard.java
public class Keyboard implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
複製代碼
Monitor.java
public class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
複製代碼
Mouse.java
public class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
複製代碼
Computer.java
public class Computer implements ComputerPart {
ComputerPart[] parts;
public Computer(){
parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
}
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
for (int i = 0; i < parts.length; i++) {
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}
複製代碼
步驟 3
定義一個表示訪問者的接口。
ComputerPartVisitor.java
public interface ComputerPartVisitor {
public void visit(Computer computer);
public void visit(Mouse mouse);
public void visit(Keyboard keyboard);
public void visit(Monitor monitor);
}
複製代碼
步驟 4
建立實現了上述類的實體訪問者。
ComputerPartDisplayVisitor.java
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
複製代碼
步驟 5
使用 ComputerPartDisplayVisitor 來顯示 Computer 的組成部分。
VisitorPatternDemo.java
public class VisitorPatternDemo {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
}
複製代碼
步驟 6
執行程序,輸出結果:
Displaying Mouse.
Displaying Keyboard.
Displaying Monitor.
Displaying Computer.
複製代碼
MVC 模式表明 Model-View-Controller(模型-視圖-控制器) 模式。這種模式用於應用程序的分層開發。
咱們將建立一個做爲模型的 Student 對象。StudentView 是一個把學生詳細信息輸出到控制檯的視圖類,StudentController 是負責存儲數據到 Student 對象中的控制器類,並相應地更新視圖 StudentView。
MVCPatternDemo,咱們的演示類使用 StudentController 來演示 MVC 模式的用法。
步驟 1
建立模型。
Student.java
public class Student {
private String rollNo;
private String name;
public String getRollNo() {
return rollNo;
}
public void setRollNo(String rollNo) {
this.rollNo = rollNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
複製代碼
步驟 2
建立視圖。
StudentView.java
public class StudentView {
public void printStudentDetails(String studentName, String studentRollNo){
System.out.println("Student: ");
System.out.println("Name: " + studentName);
System.out.println("Roll No: " + studentRollNo);
}
}
複製代碼
步驟 3
建立控制器。
StudentController.java
public class StudentController {
private Student model;
private StudentView view;
public StudentController(Student model, StudentView view){
this.model = model;
this.view = view;
}
public void setStudentName(String name){
model.setName(name);
}
public String getStudentName(){
return model.getName();
}
public void setStudentRollNo(String rollNo){
model.setRollNo(rollNo);
}
public String getStudentRollNo(){
return model.getRollNo();
}
public void updateView(){
view.printStudentDetails(model.getName(), model.getRollNo());
}
}
複製代碼
步驟 4
使用 StudentController 方法來演示 MVC 設計模式的用法。
MVCPatternDemo.java
public class MVCPatternDemo {
public static void main(String[] args) {
//從數據庫獲取學生記錄
Student model = retriveStudentFromDatabase();
//建立一個視圖:把學生詳細信息輸出到控制檯
StudentView view = new StudentView();
StudentController controller = new StudentController(model, view);
controller.updateView();
//更新模型數據
controller.setStudentName("John");
controller.updateView();
}
private static Student retriveStudentFromDatabase(){
Student student = new Student();
student.setName("Robert");
student.setRollNo("10");
return student;
}
}
複製代碼
步驟 5
執行程序,輸出結果:
Student:
Name: Robert
Roll No: 10
Student:
Name: John
Roll No: 10
複製代碼
業務表明模式(Business Delegate Pattern)用於對錶示層和業務層解耦。它基本上是用來減小通訊或對錶示層代碼中的業務層代碼的遠程查詢功能。在業務層中咱們有如下實體。
咱們將建立 Client、BusinessDelegate、BusinessService、LookUpService、JMSService 和 EJBService 來表示業務表明模式中的各類實體。
BusinessDelegatePatternDemo,咱們的演示類使用 BusinessDelegate 和 Client 來演示業務表明模式的用法。
步驟 1
建立 BusinessService 接口。
BusinessService.java
public interface BusinessService {
public void doProcessing();
}
複製代碼
步驟 2
建立實體服務類。
EJBService.java
public class EJBService implements BusinessService {
@Override
public void doProcessing() {
System.out.println("Processing task by invoking EJB Service");
}
}
複製代碼
JMSService.java
public class JMSService implements BusinessService {
@Override
public void doProcessing() {
System.out.println("Processing task by invoking JMS Service");
}
}
複製代碼
步驟 3
建立業務查詢服務。
BusinessLookUp.java
public class BusinessLookUp {
public BusinessService getBusinessService(String serviceType){
if(serviceType.equalsIgnoreCase("EJB")){
return new EJBService();
}else {
return new JMSService();
}
}
}
複製代碼
步驟 4
建立業務表明。
BusinessDelegate.java
public class BusinessDelegate {
private BusinessLookUp lookupService = new BusinessLookUp();
private BusinessService businessService;
private String serviceType;
public void setServiceType(String serviceType){
this.serviceType = serviceType;
}
public void doTask(){
businessService = lookupService.getBusinessService(serviceType);
businessService.doProcessing();
}
}
複製代碼
步驟 5
建立客戶端。
Client.java
public class Client {
BusinessDelegate businessService;
public Client(BusinessDelegate businessService){
this.businessService = businessService;
}
public void doTask(){
businessService.doTask();
}
}
複製代碼
步驟 6
使用 BusinessDelegate 和 Client 類來演示業務表明模式。
BusinessDelegatePatternDemo.java
public class BusinessDelegatePatternDemo {
public static void main(String[] args) {
BusinessDelegate businessDelegate = new BusinessDelegate();
businessDelegate.setServiceType("EJB");
Client client = new Client(businessDelegate);
client.doTask();
businessDelegate.setServiceType("JMS");
client.doTask();
}
}
複製代碼
步驟 7
執行程序,輸出結果:
Processing task by invoking EJB Service
Processing task by invoking JMS Service
複製代碼
組合實體模式(Composite Entity Pattern)用在 EJB 持久化機制中。一個組合實體是一個 EJB 實體 bean,表明了對象的圖解。當更新一個組合實體時,內部依賴對象 beans 會自動更新,由於它們是由 EJB 實體 bean 管理的。如下是組合實體 bean 的參與者。
咱們將建立做爲組合實體的 CompositeEntity 對象。CoarseGrainedObject 是一個包含依賴對象的類。
CompositeEntityPatternDemo,咱們的演示類使用 Client 類來演示組合實體模式的用法。
步驟 1
建立依賴對象。
DependentObject1.java
public class DependentObject1 {
private String data;
public void setData(String data){
this.data = data;
}
public String getData(){
return data;
}
}
複製代碼
DependentObject2.java
public class DependentObject2 {
private String data;
public void setData(String data){
this.data = data;
}
public String getData(){
return data;
}
}
複製代碼
步驟 2
建立粗粒度對象。
CoarseGrainedObject.java
public class CoarseGrainedObject {
DependentObject1 do1 = new DependentObject1();
DependentObject2 do2 = new DependentObject2();
public void setData(String data1, String data2){
do1.setData(data1);
do2.setData(data2);
}
public String[] getData(){
return new String[] {do1.getData(),do2.getData()};
}
}
複製代碼
步驟 3
建立組合實體。
CompositeEntity.java
public class CompositeEntity {
private CoarseGrainedObject cgo = new CoarseGrainedObject();
public void setData(String data1, String data2){
cgo.setData(data1, data2);
}
public String[] getData(){
return cgo.getData();
}
}
複製代碼
步驟 4
建立使用組合實體的客戶端類。
Client.java
public class Client {
private CompositeEntity compositeEntity = new CompositeEntity();
public void printData(){
for (int i = 0; i < compositeEntity.getData().length; i++) {
System.out.println("Data: " + compositeEntity.getData()[i]);
}
}
public void setData(String data1, String data2){
compositeEntity.setData(data1, data2);
}
}
複製代碼
步驟 5
使用 Client 來演示組合實體設計模式的用法。
CompositeEntityPatternDemo.java
public class CompositeEntityPatternDemo {
public static void main(String[] args) {
Client client = new Client();
client.setData("Test", "Data");
client.printData();
client.setData("Second Test", "Data1");
client.printData();
}
}
複製代碼
步驟 6
執行程序,輸出結果:
Data: Test
Data: Data
Data: Second Test
Data: Data1
複製代碼
數據訪問對象模式(Data Access Object Pattern)或 DAO 模式用於把低級的數據訪問 API 或操做從高級的業務服務中分離出來。如下是數據訪問對象模式的參與者。
咱們將建立一個做爲模型對象或數值對象的 Student 對象。StudentDao 是數據訪問對象接口。StudentDaoImpl 是實現了數據訪問對象接口的實體類。DaoPatternDemo,咱們的演示類使用 StudentDao 來演示數據訪問對象模式的用法。
步驟 1
建立數值對象。
Student.java
public class Student {
private String name;
private int rollNo;
Student(String name, int rollNo){
this.name = name;
this.rollNo = rollNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRollNo() {
return rollNo;
}
public void setRollNo(int rollNo) {
this.rollNo = rollNo;
}
}
複製代碼
步驟 2
建立數據訪問對象接口。
StudentDao.java
import java.util.List;
public interface StudentDao {
public List<Student> getAllStudents();
public Student getStudent(int rollNo);
public void updateStudent(Student student);
public void deleteStudent(Student student);
}
複製代碼
步驟 3
建立實現了上述接口的實體類。
StudentDaoImpl.java
import java.util.ArrayList;
import java.util.List;
public class StudentDaoImpl implements StudentDao {
//列表是看成一個數據庫
List<Student> students;
public StudentDaoImpl(){
students = new ArrayList<Student>();
Student student1 = new Student("Robert",0);
Student student2 = new Student("John",1);
students.add(student1);
students.add(student2);
}
@Override
public void deleteStudent(Student student) {
students.remove(student.getRollNo());
System.out.println("Student: Roll No " + student.getRollNo()
+", deleted from database");
}
//從數據庫中檢索學生名單
@Override
public List<Student> getAllStudents() {
return students;
}
@Override
public Student getStudent(int rollNo) {
return students.get(rollNo);
}
@Override
public void updateStudent(Student student) {
students.get(student.getRollNo()).setName(student.getName());
System.out.println("Student: Roll No " + student.getRollNo()
+", updated in the database");
}
}
複製代碼
步驟 4
使用 StudentDao 來演示數據訪問對象模式的用法。
DaoPatternDemo.java
public class DaoPatternDemo {
public static void main(String[] args) {
StudentDao studentDao = new StudentDaoImpl();
//輸出全部的學生
for (Student student : studentDao.getAllStudents()) {
System.out.println("Student: [RollNo : "
+student.getRollNo()+", Name : "+student.getName()+" ]");
}
//更新學生
Student student =studentDao.getAllStudents().get(0);
student.setName("Michael");
studentDao.updateStudent(student);
//獲取學生
studentDao.getStudent(0);
System.out.println("Student: [RollNo : "
+student.getRollNo()+", Name : "+student.getName()+" ]");
}
}
複製代碼
步驟 5
執行程序,輸出結果:
Student: [RollNo : 0, Name : Robert ]
Student: [RollNo : 1, Name : John ]
Student: Roll No 0, updated in the database
Student: [RollNo : 0, Name : Michael ]
複製代碼
前端控制器模式(Front Controller Pattern)是用來提供一個集中的請求處理機制,全部的請求都將由一個單一的處理程序處理。該處理程序能夠作認證/受權/記錄日誌,或者跟蹤請求,而後把請求傳給相應的處理程序。如下是這種設計模式的實體。
咱們將建立 FrontController、Dispatcher 分別看成前端控制器和調度器。HomeView 和 StudentView 表示各類爲前端控制器接收到的請求而建立的視圖。
步驟 1
建立視圖。
HomeView.java
public class HomeView {
public void show(){
System.out.println("Displaying Home Page");
}
}
複製代碼
StudentView.java
public class StudentView {
public void show(){
System.out.println("Displaying Student Page");
}
}
複製代碼
步驟 2
建立調度器 Dispatcher。
Dispatcher.java
public class Dispatcher {
private StudentView studentView;
private HomeView homeView;
public Dispatcher(){
studentView = new StudentView();
homeView = new HomeView();
}
public void dispatch(String request){
if(request.equalsIgnoreCase("STUDENT")){
studentView.show();
}else{
homeView.show();
}
}
}
複製代碼
步驟 3
建立前端控制器 FrontController。
FrontController.java
public class FrontController {
private Dispatcher dispatcher;
public FrontController(){
dispatcher = new Dispatcher();
}
private boolean isAuthenticUser(){
System.out.println("User is authenticated successfully.");
return true;
}
private void trackRequest(String request){
System.out.println("Page requested: " + request);
}
public void dispatchRequest(String request){
//記錄每個請求
trackRequest(request);
//對用戶進行身份驗證
if(isAuthenticUser()){
dispatcher.dispatch(request);
}
}
}
複製代碼
步驟 4
使用 FrontController 來演示前端控制器設計模式。
FrontControllerPatternDemo.java
public class FrontControllerPatternDemo {
public static void main(String[] args) {
FrontController frontController = new FrontController();
frontController.dispatchRequest("HOME");
frontController.dispatchRequest("STUDENT");
}
}
複製代碼
步驟 5
執行程序,輸出結果:
Page requested: HOME
User is authenticated successfully.
Displaying Home Page
Page requested: STUDENT
User is authenticated successfully.
Displaying Student Page
複製代碼
攔截過濾器模式(Intercepting Filter Pattern)用於對應用程序的請求或響應作一些預處理/後處理。定義過濾器,並在把請求傳給實際目標應用程序以前應用在請求上。過濾器能夠作認證/受權/記錄日誌,或者跟蹤請求,而後把請求傳給相應的處理程序。如下是這種設計模式的實體。
咱們將建立 FilterChain、FilterManager、Target、Client 做爲表示實體的各類對象。AuthenticationFilter 和 DebugFilter 表示實體過濾器。
InterceptingFilterDemo,咱們的演示類使用 Client 來演示攔截過濾器設計模式。
步驟 1
建立過濾器接口 Filter。
Filter.java
public interface Filter {
public void execute(String request);
}
複製代碼
步驟 2
建立實體過濾器。
AuthenticationFilter.java
public class AuthenticationFilter implements Filter {
public void execute(String request){
System.out.println("Authenticating request: " + request);
}
}
複製代碼
DebugFilter.java
public class DebugFilter implements Filter {
public void execute(String request){
System.out.println("request log: " + request);
}
}
複製代碼
步驟 3
建立 Target。
Target.java
public class Target {
public void execute(String request){
System.out.println("Executing request: " + request);
}
}
複製代碼
步驟 4
建立過濾器鏈。
FilterChain.java
import java.util.ArrayList;
import java.util.List;
public class FilterChain {
private List<Filter> filters = new ArrayList<Filter>();
private Target target;
public void addFilter(Filter filter){
filters.add(filter);
}
public void execute(String request){
for (Filter filter : filters) {
filter.execute(request);
}
target.execute(request);
}
public void setTarget(Target target){
this.target = target;
}
}
複製代碼
步驟 5
建立過濾管理器。
FilterManager.java
public class FilterManager {
FilterChain filterChain;
public FilterManager(Target target){
filterChain = new FilterChain();
filterChain.setTarget(target);
}
public void setFilter(Filter filter){
filterChain.addFilter(filter);
}
public void filterRequest(String request){
filterChain.execute(request);
}
}
複製代碼
步驟 6
建立客戶端 Client。
Client.java
public class Client {
FilterManager filterManager;
public void setFilterManager(FilterManager filterManager){
this.filterManager = filterManager;
}
public void sendRequest(String request){
filterManager.filterRequest(request);
}
}
複製代碼
步驟 7
使用 Client 來演示攔截過濾器設計模式。
InterceptingFilterDemo.java
public class InterceptingFilterDemo {
public static void main(String[] args) {
FilterManager filterManager = new FilterManager(new Target());
filterManager.setFilter(new AuthenticationFilter());
filterManager.setFilter(new DebugFilter());
Client client = new Client();
client.setFilterManager(filterManager);
client.sendRequest("HOME");
}
}
複製代碼
步驟 8
執行程序,輸出結果:
Authenticating request: HOME
request log: HOME
Executing request: HOME
複製代碼
服務定位器模式(Service Locator Pattern)用在咱們想使用 JNDI 查詢定位各類服務的時候。考慮到爲某個服務查找 JNDI 的代價很高,服務定位器模式充分利用了緩存技術。在首次請求某個服務時,服務定位器在 JNDI 中查找服務,並緩存該服務對象。當再次請求相同的服務時,服務定位器會在它的緩存中查找,這樣能夠在很大程度上提升應用程序的性能。如下是這種設計模式的實體。
咱們將建立 ServiceLocator、InitialContext、Cache、Service 做爲表示實體的各類對象。Service1 和 Service2 表示實體服務。
ServiceLocatorPatternDemo,咱們的演示類在這裏是做爲一個客戶端,將使用 ServiceLocator 來演示服務定位器設計模式。
步驟 1
建立服務接口 Service。
Service.java
public interface Service {
public String getName();
public void execute();
}
複製代碼
步驟 2
建立實體服務。
Service1.java
public class Service1 implements Service {
public void execute(){
System.out.println("Executing Service1");
}
@Override
public String getName() {
return "Service1";
}
}
複製代碼
Service2.java
public class Service2 implements Service {
public void execute(){
System.out.println("Executing Service2");
}
@Override
public String getName() {
return "Service2";
}
}
複製代碼
步驟 3
爲 JNDI 查詢建立 InitialContext。
InitialContext.java
public class InitialContext {
public Object lookup(String jndiName){
if(jndiName.equalsIgnoreCase("SERVICE1")){
System.out.println("Looking up and creating a new Service1 object");
return new Service1();
}else if (jndiName.equalsIgnoreCase("SERVICE2")){
System.out.println("Looking up and creating a new Service2 object");
return new Service2();
}
return null;
}
}
複製代碼
步驟 4
建立緩存 Cache。
Cache.java
import java.util.ArrayList;
import java.util.List;
public class Cache {
private List<Service> services;
public Cache(){
services = new ArrayList<Service>();
}
public Service getService(String serviceName){
for (Service service : services) {
if(service.getName().equalsIgnoreCase(serviceName)){
System.out.println("Returning cached "+serviceName+" object");
return service;
}
}
return null;
}
public void addService(Service newService){
boolean exists = false;
for (Service service : services) {
if(service.getName().equalsIgnoreCase(newService.getName())){
exists = true;
}
}
if(!exists){
services.add(newService);
}
}
}
複製代碼
步驟 5
建立服務定位器。
ServiceLocator.java
public class ServiceLocator {
private static Cache cache;
static {
cache = new Cache();
}
public static Service getService(String jndiName){
Service service = cache.getService(jndiName);
if(service != null){
return service;
}
InitialContext context = new InitialContext();
Service service1 = (Service)context.lookup(jndiName);
cache.addService(service1);
return service1;
}
}
複製代碼
步驟 6
使用 ServiceLocator 來演示服務定位器設計模式。
ServiceLocatorPatternDemo.java
public class ServiceLocatorPatternDemo {
public static void main(String[] args) {
Service service = ServiceLocator.getService("Service1");
service.execute();
service = ServiceLocator.getService("Service2");
service.execute();
service = ServiceLocator.getService("Service1");
service.execute();
service = ServiceLocator.getService("Service2");
service.execute();
}
}
複製代碼
步驟 7
執行程序,輸出結果:
Looking up and creating a new Service1 object
Executing Service1
Looking up and creating a new Service2 object
Executing Service2
Returning cached Service1 object
Executing Service1
Returning cached Service2 object
Executing Service2
複製代碼
傳輸對象模式(Transfer Object Pattern)用於從客戶端向服務器一次性傳遞帶有多個屬性的數據。傳輸對象也被稱爲數值對象。傳輸對象是一個具備 getter/setter 方法的簡單的 POJO 類,它是可序列化的,因此它能夠經過網絡傳輸。它沒有任何的行爲。服務器端的業務類一般從數據庫讀取數據,而後填充 POJO,並把它發送到客戶端或按值傳遞它。對於客戶端,傳輸對象是隻讀的。客戶端能夠建立本身的傳輸對象,並把它傳遞給服務器,以便一次性更新數據庫中的數值。如下是這種設計模式的實體。
咱們將建立一個做爲業務對象的 StudentBO 和做爲傳輸對象的 StudentVO,它們都表明了咱們的實體。
TransferObjectPatternDemo,咱們的演示類在這裏是做爲一個客戶端,將使用 StudentBO 和 Student 來演示傳輸對象設計模式。
步驟 1
建立傳輸對象。
StudentVO.java
public class StudentVO {
private String name;
private int rollNo;
StudentVO(String name, int rollNo){
this.name = name;
this.rollNo = rollNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRollNo() {
return rollNo;
}
public void setRollNo(int rollNo) {
this.rollNo = rollNo;
}
}
複製代碼
步驟 2
建立業務對象。
StudentBO.java
import java.util.ArrayList;
import java.util.List;
public class StudentBO {
//列表是看成一個數據庫
List<StudentVO> students;
public StudentBO(){
students = new ArrayList<StudentVO>();
StudentVO student1 = new StudentVO("Robert",0);
StudentVO student2 = new StudentVO("John",1);
students.add(student1);
students.add(student2);
}
public void deleteStudent(StudentVO student) {
students.remove(student.getRollNo());
System.out.println("Student: Roll No "
+ student.getRollNo() +", deleted from database");
}
//從數據庫中檢索學生名單
public List<StudentVO> getAllStudents() {
return students;
}
public StudentVO getStudent(int rollNo) {
return students.get(rollNo);
}
public void updateStudent(StudentVO student) {
students.get(student.getRollNo()).setName(student.getName());
System.out.println("Student: Roll No "
+ student.getRollNo() +", updated in the database");
}
}
複製代碼
步驟 3
使用 StudentBO 來演示傳輸對象設計模式。
TransferObjectPatternDemo.java
public class TransferObjectPatternDemo {
public static void main(String[] args) {
StudentBO studentBusinessObject = new StudentBO();
//輸出全部的學生
for (StudentVO student : studentBusinessObject.getAllStudents()) {
System.out.println("Student: [RollNo : "
+student.getRollNo()+", Name : "+student.getName()+" ]");
}
//更新學生
StudentVO student =studentBusinessObject.getAllStudents().get(0);
student.setName("Michael");
studentBusinessObject.updateStudent(student);
//獲取學生
studentBusinessObject.getStudent(0);
System.out.println("Student: [RollNo : "
+student.getRollNo()+", Name : "+student.getName()+" ]");
}
}
複製代碼
步驟 4
執行程序,輸出結果:
Student: [RollNo : 0, Name : Robert ]
Student: [RollNo : 1, Name : John ]
Student: Roll No 0, updated in the database
Student: [RollNo : 0, Name : Michael ]
複製代碼