設(shè)計(jì)模式2

外觀模式 :

迪米特法則(最少知識(shí)原則) : 一個(gè)軟件實(shí)體應(yīng)當(dāng)盡可能少的與其他實(shí)體發(fā)送相互作用.

外觀模式核心 : 為子系統(tǒng)提高統(tǒng)一的入口,封裝子系統(tǒng)的復(fù)雜性,便于客戶端調(diào)用.

開發(fā)中常見的場(chǎng)景 :

頻率很高.哪里都會(huì)遇到.各種技術(shù)和框架中,都有外觀模式的使用.如 : JDBC封裝后的,commons提供的DBUtils類,Hibernate提供的工具類,Spring JDBC工具類等.

享元模式(FlyWeight) :

場(chǎng)景 : 內(nèi)存屬于稀缺資源,不要隨便浪費(fèi).如果有很多個(gè)完全相同或相似的對(duì)象,我們可以通過享元模式,節(jié)省內(nèi)存.

核心 : 享元模式以共享的方式高效的支持大量細(xì)粒度對(duì)象的重用.

享元模式能做到共享的關(guān)鍵和區(qū)分了內(nèi)部狀態(tài)和外部狀態(tài).

內(nèi)部狀態(tài) : 可以共享,不會(huì)隨環(huán)境變化而改變.

外部狀態(tài) : 不可以共享,會(huì)隨環(huán)境變化而改變.

享元模式實(shí)現(xiàn) :

FlyweightFactory享元工廠類 : 創(chuàng)建并管理享元對(duì)象,享元池一般設(shè)計(jì)成鍵值對(duì).

FlyWeight抽象享元類 : 通常是一個(gè)接口或抽象類,聲明公共方法,這些方法可以向外界提供對(duì)象的內(nèi)部狀態(tài),設(shè)置外部狀態(tài).

ConcreteFlyWeight具體享元類 : 為內(nèi)部狀態(tài)提供成員變量進(jìn)行存儲(chǔ).

UnsharedConcreteFlyWeight非共享享元類 : 不能被共享的子類可以設(shè)計(jì)為非共享享元類.

享元模式開發(fā)中應(yīng)用的場(chǎng)景 :

享元模式由于其共享的特性,可以再任何'池'中操作,比如 : 線程池,數(shù)據(jù)庫(kù)連接池.String類的設(shè)計(jì)也是享元模式.

優(yōu)點(diǎn) :

極大減少內(nèi)存中對(duì)象的數(shù)量;

相同或相似對(duì)象內(nèi)存中只存一份,極大的節(jié)約資源,提供系統(tǒng)性能;

外部狀態(tài)相對(duì)獨(dú)立,不影響內(nèi)部狀態(tài).

缺點(diǎn) :

模式較復(fù)雜,使程序邏輯復(fù)雜化;

為了節(jié)省內(nèi)存,共享了內(nèi)部狀態(tài),分離出外部狀態(tài),而讀取外部狀態(tài)使運(yùn)行時(shí)間變長(zhǎng).用時(shí)間換取了空間.

例子 :

package com.example.demo.flyweight;

/**

* 享元類

*/

public interface ChessFlyWeight {

void setColor(String c);

String getColor();

void display(Coordinate c);

}

class ConcreteChess implements ChessFlyWeight {

private String color;

public ConcreteChess(String color) {

this.color = color;

}

@Override

public void setColor(String c) {

this.color = c;

}

@Override

public String getColor() {

return color;

}

@Override

public void display(Coordinate coordinate) {

System.out.println("棋子顏色 : " + color);

System.out.println("棋子位置 : " + coordinate.getX() + "-----" + coordinate.getY());

}

}

package com.example.demo.flyweight;

import java.util.HashMap;

import java.util.Map;

/**

* 享元工廠類

*/

public class ChessFlyWeightFactory {

// 享元池

private static Map<String, ChessFlyWeight> map = new HashMap<>();

public static ChessFlyWeight getChess(String color) {

if (map.get(color) != null) {

return map.get(color);

} else {

ChessFlyWeight cfw = new ConcreteChess(color);

map.put(color, cfw);

return cfw;

}

}

}

package com.example.demo.flyweight;

/**

* 外部狀態(tài)UnSharedConcreteFlyWeight

*/

public class Coordinate {

private int x,y;

public Coordinate(int x, int y) {

this.x = x;

this.y = y;

}

public int getX() {

return x;

}

public void setX(int x) {

this.x = x;

}

public int getY() {

return y;

}

public void setY(int y) {

this.y = y;

}

}

package com.example.demo.flyweight;

public class Client {

public static void main(String[] args) {

ChessFlyWeight chess1 = ChessFlyWeightFactory.getChess("黑色");

ChessFlyWeight chess2 = ChessFlyWeightFactory.getChess("黑色");

System.out.println(chess1);

System.out.println(chess2);

System.out.println("增加外部狀態(tài)的處理======");

chess1.display(new Coordinate(10, 10));

chess2.display(new Coordinate(20, 20));

}

}

結(jié)構(gòu)型模式匯總 :

代理模式 : 為真實(shí)對(duì)象提供一個(gè)代理,從而控制對(duì)真實(shí)對(duì)象的訪問;

適配模式 : 使原本由于接口不兼容不能一起工作的類可以一起工作;

橋接模式 : 處理多層繼承結(jié)構(gòu),處理多維度變化的場(chǎng)景,將各個(gè)維度設(shè)計(jì)成獨(dú)立的繼承結(jié)構(gòu),使各個(gè)維度可以獨(dú)立的擴(kuò)展在抽象層建立關(guān)聯(lián).

組合模式 : 將對(duì)象組合成樹狀結(jié)構(gòu)以表示"部分和整體"層次結(jié)構(gòu),使得客戶可以統(tǒng)一的調(diào)用葉子對(duì)象和容器對(duì)象.

裝飾模式 : 動(dòng)態(tài)的給一個(gè)對(duì)象添加額外的功能,比繼承靈活.

外觀模式 : 為子系統(tǒng)提供統(tǒng)一的調(diào)用接口,使得子系統(tǒng)更加容易使用.

享元模式 : 運(yùn)用共享技術(shù)有效的實(shí)現(xiàn)管理大量細(xì)粒度對(duì)象,節(jié)省內(nèi)存,提供效率.

創(chuàng)建型模式關(guān)注對(duì)象的創(chuàng)建過程.

結(jié)構(gòu)型模式關(guān)注對(duì)象和類的組織.

行為型模式 :

關(guān)注系統(tǒng)中對(duì)象之間的相互交互,研究系統(tǒng)在運(yùn)行時(shí)對(duì)象之間 的相互通信和協(xié)作,進(jìn)一步明確對(duì)象的職責(zé),共有11種模式.

行為型模式匯總 :

(1) 責(zé)任鏈模式 chain of responsibility

(2) 命令模式 command

(3) 解釋器模式 interpreter

(4) 迭代器模式 iterator

(5) 中介者模式 mediator

(6) 備忘錄模式 memento

(7) 觀察者模式 observer

(8) 狀態(tài)模式 state

(9) 策略模式 strategy

(10) 模板方法模式 template method

(11) 訪問者模式 visitor

責(zé)任鏈模式(chain or responsibility) :

定義 : 將能夠處理同一類請(qǐng)求的對(duì)象連成一條鏈,所提交的請(qǐng)求沿著鏈傳遞,鏈上的對(duì)象逐個(gè)判斷是否有能力處理該請(qǐng)求,如果能則處理,如果不能則傳遞給鏈上的下一個(gè)對(duì)象.

場(chǎng)景 :

打牌時(shí),輪流出牌;接力賽跑;大學(xué)中,獎(jiǎng)學(xué)金審批;公司中,公文審批;

添加新的處理對(duì)象 :

由于責(zé)任鏈的創(chuàng)建完成在客戶端,因此新增新的具體處理這對(duì)原有類庫(kù)沒有任何影響,只需添加新的類,然后再客戶端調(diào)用時(shí)添加即可.符合開閉原則.

鏈表方式定義責(zé)任鏈 :

非鏈表方式實(shí)現(xiàn)責(zé)任鏈 : 通過集合,數(shù)組生成責(zé)任鏈更加實(shí)用!實(shí)際上,很多項(xiàng)目中,每個(gè)具體的Handler并不是開發(fā)團(tuán)隊(duì)定義的,而是項(xiàng)目上線后由外部單位追加的,

所以使用鏈表方式訂閱COR鏈就很困難.

開發(fā)中常見的場(chǎng)景 :

Java中,異常機(jī)制就是一種責(zé)任鏈模式.一個(gè)try可以對(duì)應(yīng)多個(gè)catch,當(dāng)?shù)谝粋€(gè)catch不匹配類型,則自動(dòng)跳到第二個(gè)catch.

JavaScript語(yǔ)言中,事件的冒泡和捕獲機(jī)制.Java語(yǔ)言中,事件的處理采用觀察者模式.

Servlet開發(fā)中,過濾器的鏈?zhǔn)教幚?

Struts2中,攔截器的調(diào)用也是典型的責(zé)任鏈模式.

例子中 :

package com.example.demo.chainOfResp;

/**

* 封裝請(qǐng)假的基本信息

*/

public class LeaveRequest {

private String empName;

private int leaveDays;

private String reason;

public LeaveRequest(String empName, int leaveDays, String reason) {

super();

this.empName = empName;

this.leaveDays = leaveDays;

this.reason = reason;

}

public String getEmpName() {

return empName;

}

public void setEmpName(String empName) {

this.empName = empName;

}

public int getLeaveDays() {

return leaveDays;

}

public void setLeaveDays(int leaveDays) {

this.leaveDays = leaveDays;

}

public String getReason() {

return reason;

}

public void setReason(String reason) {

this.reason = reason;

}

}

package com.example.demo.chainOfResp;

/**

* 主任

*/

public class Director extends Leader {

public Director(String name) {

super(name);

}

@Override

public void handleRequest(LeaveRequest request) {

if (request.getLeaveDays() < 3) {

System.out.println("員工 : " + request.getEmpName() + "請(qǐng)假,天數(shù) : " + request.getLeaveDays() + ", 理由 : " + request.getReason());

System.out.println("主任 : " + this.name + ", 審批通過!");

} else {

if (this.nextLeader != null) {

this.nextLeader.handleRequest(request);

}

}

}

}

package com.example.demo.chainOfResp;

/**

* 副總

*/

public class ViceGeneralManager extends Leader {

public ViceGeneralManager(String name) {

super(name);

}

@Override

public void handleRequest(LeaveRequest request) {

if (request.getLeaveDays() < 60) {

System.out.println("員工 : " + request.getEmpName() + "請(qǐng)假,天數(shù) : " + request.getLeaveDays() + ", 理由 : " + request.getReason());

System.out.println("總經(jīng)理 : " + this.name + ", 審批通過!");

} else {

System.out.println("無法申請(qǐng)請(qǐng)假!");

}

}

}

package com.example.demo.chainOfResp;

public class GeneralManager extends Leader {

public GeneralManager(String name) {

super(name);

}

@Override

public void handleRequest(LeaveRequest request) {

if (request.getLeaveDays() < 30) {

System.out.println("員工 : " + request.getEmpName() + "請(qǐng)假,天數(shù) : " + request.getLeaveDays() + ", 理由 : " + request.getReason());

System.out.println("總經(jīng)理 : " + this.name + ", 審批通過!");

} else {

if (this.nextLeader != null) {

this.nextLeader.handleRequest(request);

}

}

}

}

package com.example.demo.chainOfResp;

/**

* 抽象類

*/

public abstract class Leader {

protected String name;

// 責(zé)任鏈上后繼對(duì)象

protected Leader nextLeader;

public Leader(String name) {

this.name = name;

}

// 設(shè)定責(zé)任鏈上的后繼對(duì)象

public void setNextLeader(Leader nextLeader) {

this.nextLeader = nextLeader;

}

/**

* 處理請(qǐng)求的核心的業(yè)務(wù)方法

*/

public abstract void handleRequest(LeaveRequest request);

}

package com.example.demo.chainOfResp;

/**

* 經(jīng)理

*/

public class Manager extends Leader {

public Manager(String name) {

super(name);

}

@Override

public void handleRequest(LeaveRequest request) {

if (request.getLeaveDays() < 10) {

System.out.println("員工 : " + request.getEmpName() + "請(qǐng)假,天數(shù) : " + request.getLeaveDays() + ", 理由 : " + request.getReason());

System.out.println("經(jīng)理 : " + this.name + ", 審批通過!");

} else {

if (this.nextLeader != null) {

this.nextLeader.handleRequest(request);

}

}

}

}

package com.example.demo.chainOfResp;

public class Client {

public static void main(String[] args) {

Leader a = new Director("張三");

Leader b = new Manager("李四");

Leader c = new GeneralManager("王五");

Leader d = new ViceGeneralManager("張強(qiáng)");

// 組織責(zé)任鏈對(duì)象的關(guān)系

a.setNextLeader(b);

b.setNextLeader(c);

c.setNextLeader(d);

// 開始請(qǐng)假操作

LeaveRequest request = new LeaveRequest("TOM", 30, "回家");

a.handleRequest(request);

}

}

迭代器模式(iterator)

場(chǎng)景 :

提供一種可以遍歷聚合對(duì)象的方式.又稱為 : 游標(biāo)cursor模式;

聚合對(duì)象 : 存儲(chǔ)數(shù)據(jù);

迭代器 : 遍歷數(shù)據(jù)

基本案例 :

實(shí)現(xiàn)正向遍歷的迭代器;

實(shí)現(xiàn)逆向遍歷的迭代器;

開發(fā)中常見的場(chǎng)景 :

JDK內(nèi)置的迭代器(List/Set)

例子 :

package com.example.demo.iterator;

/**

* 自定義的迭代器接口

*/

public interface MyIterator {

// 將游標(biāo)指向第一個(gè)元素

void first();

// 將游標(biāo)指向下一個(gè)元素

void next();

// 判斷是否存在下一個(gè)元素

boolean hasNext();

boolean isFirst();

boolean isLast();

// 獲取當(dāng)前游標(biāo)指向的對(duì)象

Object getCurrentObj();

}

package com.example.demo.iterator;

import java.util.ArrayList;

import java.util.List;

/**

* 自定義的聚合類

*/

public class ConcreteMyAggregate {

private List<Object> list = new ArrayList<Object>();

public ConcreteMyAggregate() {

super();

}

public void addObject(Object obj) {

this.list.add(obj);

}

public void removeObject(Object obj) {

this.list.remove(obj);

}

public List<Object> getList() {

return list;

}

public void setList(List<Object> list) {

this.list = list;

}

// 獲得迭代器

public MyIterator createIterator() {

return new ConcreteIterator();

}

// 使用內(nèi)部類訂閱迭代器,可以直接使用外部類的屬性

private class ConcreteIterator implements MyIterator {

// 定義游標(biāo)用于記錄遍歷時(shí)的位置

private int cursor;

@Override

public void first() {

cursor = 0;

}

@Override

public void next() {

if (cursor < list.size()) {

cursor++;

}

}

@Override

public boolean hasNext() {

if (cursor < list.size()) {

return true;

}

return false;

}

@Override

public boolean isFirst() {

return cursor == 0 ? true : false;

}

@Override

public boolean isLast() {

return cursor == (list.size() - 1) ? true : false;

}

@Override

public Object getCurrentObj() {

return list.get(cursor);

}

}

}

package com.example.demo.iterator;

public class Client {

public static void main(String[] args) {

ConcreteMyAggregate cma = new ConcreteMyAggregate();

cma.addObject("aa");

cma.addObject("bb");

cma.addObject("cc");

MyIterator iterator = cma.createIterator();

while (iterator.hasNext()) {

System.out.println(iterator.getCurrentObj());

iterator.next();

}

}

}

中介者模式(Mediator) :

核心 :

如果一個(gè)系統(tǒng)中對(duì)象之間的聯(lián)系呈現(xiàn)為網(wǎng)狀結(jié)構(gòu),對(duì)象之間存在大量多對(duì)多關(guān)系,將導(dǎo)致關(guān)系及其復(fù)雜,這些對(duì)象稱為"同事對(duì)象";

我們可以引入一個(gè)中介者對(duì)象,使各個(gè)同事對(duì)象只跟中介者對(duì)象打交道,將復(fù)雜的網(wǎng)絡(luò)結(jié)構(gòu)化解為星形結(jié)構(gòu).

中介者模式的本質(zhì) :

解耦多個(gè)同事對(duì)象之間的交互關(guān)系.每個(gè)對(duì)象都持有中介者對(duì)象的引用,只跟中介者對(duì)象打交道.我們通過中介者對(duì)象統(tǒng)一管理這些交互關(guān)系.

開發(fā)中常見的場(chǎng)景 :

MVC模式(其中的C,控制器就是一個(gè)中介者對(duì)象.M和V都和他打交道);

窗口游戲程序,窗口軟件開發(fā)中窗口對(duì)象也是一個(gè)中介者對(duì)象;

圖像界面開發(fā)GUI中,多個(gè)組件之間的交互,可以通過引入一個(gè)中介者對(duì)象來解決,可以是整體的窗口對(duì)象或者DOM對(duì)象.

Java.lang.reflect.Method#invoke()

例子 :

package com.example.demo.mediator;

// 中介者

public interface Mediator {

void register(String dname, Department d);

void command(String dname);

}

package com.example.demo.mediator;

import java.util.HashMap;

import java.util.Map;

public class President implements Mediator {

private Map<String, Department> map = new HashMap<>();

@Override

public void register(String dname, Department d) {

map.put(dname, d);

}

@Override

public void command(String dname) {

map.get(dname);

}

}

package com.example.demo.mediator;

// 同事類的接口

public interface Department {

// 做本部門的事情

void selfAction();

// 向總經(jīng)理發(fā)出申請(qǐng)

void outAction();

}

package com.example.demo.mediator;

public class Development implements Department {

// 持有中介者的引用

private Mediator m;

public Development(Mediator m) {

this.m = m;

m.register("development", this);

}

@Override

public void selfAction() {

System.out.println("匯報(bào)工作!沒錢了,需要資金支持!");

}

@Override

public void outAction() {

System.out.println("專心科研,開發(fā)項(xiàng)目!");

}

}

package com.example.demo.mediator;

public class Finacial implements Department {

// 持有中介者(總經(jīng)理)的引用

private Mediator m;

public Finacial(Mediator m) {

this.m = m;

m.register("finacial", this);

}

@Override

public void selfAction() {

System.out.println("匯報(bào)工作!沒錢了,錢太多了!怎么花?");

}

@Override

public void outAction() {

System.out.println("數(shù)錢!");

}

}

package com.example.demo.mediator;

public class Market implements Department {

// 持有中介者(總經(jīng)理)的引用

private Mediator m;

public Market(Mediator m) {

this.m = m;

m.register("market", this);

}

@Override

public void selfAction() {

System.out.println("匯報(bào)工作!項(xiàng)目承接的進(jìn)度,需要資金支持!");

}

@Override

public void outAction() {

System.out.println("跑去接項(xiàng)目!");

m.command("finacial");

}

}

package com.example.demo.mediator;

public class Client {

public static void main(String[] args) {

Mediator m = new President();

Market market = new Market(m);

Development development = new Development(m);

Finacial finacial = new Finacial(m);

market.selfAction();

market.outAction();

}

}

命令模式(command) :

介紹 :

命令模式 : 將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使我們可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或者記錄請(qǐng)求日志,以及支持可撤銷的操作.也稱之為 : 動(dòng)作

Action模式,事務(wù)transaction模式;

結(jié)構(gòu) :

Command抽象命令類;

ConcreteCommand具體命令類;

Invoker調(diào)用者/請(qǐng)求者 :

請(qǐng)求的發(fā)送者,它通過命令對(duì)象來執(zhí)行請(qǐng)求.一個(gè)調(diào)用者并不需要在設(shè)計(jì)時(shí)確定其接收者,因此它只與抽象命令類之間存在關(guān)聯(lián).在程序運(yùn)行時(shí),將調(diào)用命令對(duì)象的

execute(),間接調(diào)用接收者的相關(guān)操作.

Receiver接收者 :

接收者執(zhí)行與請(qǐng)求相關(guān)的操作,具體實(shí)現(xiàn)對(duì)請(qǐng)求的業(yè)務(wù)處理.

未抽象前,實(shí)際執(zhí)行操作內(nèi)容的對(duì)象.

Client客戶類 :

在客戶類中需要?jiǎng)?chuàng)建調(diào)用者對(duì)象,具體命令類對(duì)象,在創(chuàng)建具體命令對(duì)象時(shí)指定對(duì)應(yīng)的接收者.發(fā)送者和接收者之間沒有直接關(guān)系,都通過命令對(duì)象間接調(diào)用.

開發(fā)中常見的場(chǎng)景 :

Struts2,action的整個(gè)調(diào)用過程中就有命令模式.

數(shù)據(jù)庫(kù)事務(wù)機(jī)制的底層實(shí)現(xiàn);

命令的撤銷和恢復(fù).

例子 :

package com.example.demo.command;

/**

* 真正的命令的執(zhí)行者

*/

public class Receiver {

public void action() {

System.out.println("Receiver.action()");

}

}

package com.example.demo.command;

public interface Command {

/**

* 這個(gè)方法是一個(gè)返回結(jié)果為空的方法.

* 實(shí)際項(xiàng)目中,可以根據(jù)需求設(shè)計(jì)多個(gè)不同的方法

*/

void execute();

}

class ConcreteCommand implements Command {

// 命令的真正執(zhí)行者

private Receiver receiver;

public ConcreteCommand(Receiver receiver) {

this.receiver = receiver;

}

@Override

public void execute() {

// 命令真正執(zhí)行前或后,執(zhí)行相關(guān)的處理!

receiver.action();

}

}

package com.example.demo.command;

/**

* 調(diào)用者/發(fā)起者

*/

public class Invoke {

// 也可以通過容器List<Command>容納很多命令對(duì)象,進(jìn)行批處理.數(shù)據(jù)庫(kù)底層的事務(wù)管理就是類似的結(jié)構(gòu)!

private Command command;

public Invoke(Command command) {

this.command = command;

}

// 業(yè)務(wù)方法,用于調(diào)用命令類的方法

public void call() {

command.execute();

}

}

package com.example.demo.command;

public class Client {

public static void main(String[] args) {

Command command = new ConcreteCommand(new Receiver());

Invoke invoke = new Invoke(command);

invoke.call();

}

}

解釋器模式(Interpreter)

介紹 :

是一種不常用的設(shè)計(jì)模式;

用于描述如何構(gòu)成一個(gè)簡(jiǎn)單的語(yǔ)言解釋器,主要用于使用面向?qū)ο笳Z(yǔ)言開發(fā)的編譯器和解釋器設(shè)計(jì).

當(dāng)我們需要開發(fā)一種新的語(yǔ)言時(shí),可以考慮使用解釋器模式.

盡量不要使用解釋器模式,后期維護(hù)會(huì)有很大麻煩.在項(xiàng)目中,可以使用Jruby,Groovy,java的js引擎來替代解釋器的作用,彌補(bǔ)java語(yǔ)言的不足.

開發(fā)中常見的場(chǎng)景 :

EL表達(dá)式的處理;正則表達(dá)式的解釋器;SQL語(yǔ)法的解釋器;數(shù)學(xué)表達(dá)式解釋器;如現(xiàn)成的工具包 : Math Expression String Parser ,Expression4J等.

MESP的網(wǎng)址 :

Expression4J的網(wǎng)址 :

訪問者模式Visitor :

模式動(dòng)機(jī) :

對(duì)于存儲(chǔ)在一個(gè)集合中的對(duì)象,他們可能具有不同的類型(即使有一個(gè)公共的接口),對(duì)于該集合中的對(duì)象,可以接受一類稱為訪問者的對(duì)象來訪問,不同的訪問者其

訪問方式也有所不同.

定義 :

表示一個(gè)作業(yè)于某個(gè)對(duì)象結(jié)構(gòu)中的各元素的操作,它使我們可以在不改變個(gè)元素的類的前提下定義作業(yè)于這些元素的新操作.

開發(fā)中的場(chǎng)景(應(yīng)用范圍非常窄,了解即可) :

XML文檔解析器設(shè)計(jì);編譯器的設(shè)計(jì);復(fù)雜集合對(duì)象的處理;

策略模式 :

策略模式對(duì)應(yīng)于解決某一個(gè)問題的一個(gè)算法族,允許用戶從該算法族中任選一個(gè)算法解決某一問題,同時(shí)可以方便的更換算法或者增加新的算法.并且由客戶端覺得調(diào)用哪個(gè)算法.

本質(zhì) :

分離算法,選擇實(shí)現(xiàn);

開發(fā)中常見的場(chǎng)景 :

JAVASE中GUI編程中,布局管理;Spring框架中,Resource接口,資源訪問策略;javax.servlet.httpServlet#service();

例子 :

package com.example.demo.strategy;

public interface Strategy {

public double getPrice(double standardPrice);

}

package com.example.demo.strategy;

public class NewCustomerFewStrategy implements Strategy {

@Override

public double getPrice(double standardPrice) {

System.out.println("不打折,原價(jià)!");

return standardPrice;

}

}

package com.example.demo.strategy;

public class NewCustomerManyStrategy implements Strategy {

@Override

public double getPrice(double standardPrice) {

System.out.println("打九折!");

return standardPrice*0.9;

}

}

package com.example.demo.strategy;

public class OldCustomerManyStrategy implements Strategy {

@Override

public double getPrice(double standardPrice) {

System.out.println("打八折!");

return standardPrice*0.8;

}

}

package com.example.demo.strategy;

public class OldCustomerFewStrategy implements Strategy {

@Override

public double getPrice(double standardPrice) {

System.out.println("打八五折!");

return standardPrice*0.85;

}

}

package com.example.demo.strategy;

/**

* 負(fù)責(zé)和具體的策略類交互

* 這樣的話,具體的算法和直接的客戶端調(diào)用分離了,使得算法可以獨(dú)立于客戶端獨(dú)立的變化

* 如果使用spring的依賴注入功能,換可以通過配置文件,動(dòng)態(tài)的注入不同策略對(duì)象,動(dòng)態(tài)的切換不同的算法.

*/

public class Context {

// 當(dāng)前采用的算法對(duì)象

private Strategy strategy;

// 可以通過構(gòu)造器來注入

public Context(Strategy strategy) {

this.strategy = strategy;

}

public void setStrategy(Strategy strategy) {

this.strategy = strategy;

}

public void pringPrice(double s) {

System.out.println("您該報(bào)價(jià) : " + strategy.getPrice(s));

}

}

package com.example.demo.strategy;

public class Client {

public static void main(String[] args) {

Strategy s1 = new OldCustomerManyStrategy();

Context context = new Context(s1);

context.pringPrice(998);

}

}

模板方法模式(template method)

模板方法模式介紹 :

模板方法模式是編程中經(jīng)常用得到模式.它定義了一個(gè)操作中的算法骨架,將某些步驟延遲到子類中實(shí)現(xiàn).這樣,新的子類可以在不改變一個(gè)算法結(jié)構(gòu)的前提下重新

定義該算法的某些特定步驟.

核心 :

處理某個(gè)流程的代碼已經(jīng)都具備,但是其中某個(gè)節(jié)點(diǎn)的代碼暫時(shí)不能確定.因此,我們采用工廠方法模式,將這個(gè)節(jié)點(diǎn)的代碼實(shí)現(xiàn)轉(zhuǎn)移給子類完成.既 : 處理步驟父類

中定義好,具體實(shí)現(xiàn)延遲到子類中定義.

方法回調(diào)(鉤子方法)

在好萊塢,當(dāng)藝人把簡(jiǎn)歷提交給好萊塢的娛樂公司時(shí),所能做的就是等待,整個(gè)過程由娛樂公司控制,演員只能被動(dòng)的服務(wù)安排,在需要的時(shí)候再由公司安排具體環(huán)節(jié)的

演出.

在軟件開發(fā)中,我們可以將call翻譯為調(diào)用.子類不能調(diào)用父類,而通過父類調(diào)用子類.這些調(diào)用步驟已經(jīng)在父類中寫好了,完全由父類控制整個(gè)過程.

什么時(shí)候用到模板方法模式 :

實(shí)現(xiàn)一個(gè)算法時(shí),整體步驟很固定.但是,某些部分易變.易變部分可以抽象出來,供子類實(shí)現(xiàn).

開發(fā)中常見的場(chǎng)景 :

非常頻繁.各個(gè)框架,類庫(kù)中都有他的影子.比如常見的有 :

數(shù)據(jù)庫(kù)訪問的封裝;Junit單元測(cè)試;servlet中關(guān)于doGet/doPost方法調(diào)用;Hibernate中模板程序;spring中JDBCTemplate,HibernateTemplate等.

例子 :

package com.example.demo.templateMethod;

public abstract class BankTemplateMethod {

// 具體方法

public void takeNumber() {

System.out.println("取號(hào)排隊(duì)!");

}

// 辦理具體的業(yè)務(wù) //鉤子方法

public abstract void transact();

public void evaluate() {

System.out.println("反饋評(píng)分");

}

// 模板方法,把基本操作組合到一起,子類一般不能重寫.

public final void process() {

this.takeNumber();

// 像個(gè)鉤子,執(zhí)行時(shí),掛那個(gè)子類的方法就調(diào)用哪個(gè).

this.transact();

this.evaluate();

}

}

package com.example.demo.templateMethod;

public class client {

public static void main(String[] args) {

BankTemplateMethod bankTemplateMethod? = new DrawMoney();

bankTemplateMethod.process();

System.out.println("----------------------");

// 采用匿名內(nèi)部類

BankTemplateMethod bankTemplateMethod1 = new BankTemplateMethod() {

@Override

public void transact() {

System.out.println("我要存錢");

}

};

bankTemplateMethod1.process();

}

}

class DrawMoney extends BankTemplateMethod {

@Override

public void transact() {

System.out.println("我要取款!!!");

}

}

狀態(tài)模式(state)

核心 : 用于解決系統(tǒng)中復(fù)雜對(duì)象的狀態(tài)轉(zhuǎn)換以及不同狀態(tài)下行為的封裝問題;

結(jié)構(gòu) : Context環(huán)境類(環(huán)境類中維護(hù)一個(gè)State對(duì)象,他是定義了當(dāng)前的狀態(tài).);State抽象狀態(tài)類;ConcreteState具體狀態(tài)類(每一個(gè)類封裝了一個(gè)狀態(tài)對(duì)應(yīng)的行為);

開發(fā)中常見的場(chǎng)景 :

銀行系統(tǒng)中賬號(hào)狀態(tài)的管理;OA系統(tǒng)中公文狀態(tài)的管理;酒店系統(tǒng)中,房間狀態(tài)的管理;線程對(duì)象各狀態(tài)之間的切換.

例子 :

package com.example.demo.state;

public interface State {

void handle();

}

package com.example.demo.state;

/**

* 空閑狀態(tài)

*/

public class FreeState implements? State{

@Override

public void handle() {

System.out.println("房間空閑!!!沒人住.");

}

}

package com.example.demo.state;

/**

* 已預(yù)訂狀態(tài)

*/

public class BookedState implements State {

@Override

public void handle() {

System.out.println("房間已預(yù)訂!別人不能定!");

}

}

package com.example.demo.state;

/**

* 已入住狀態(tài)

*/

public class CheckedInState implements State {

@Override

public void handle() {

System.out.println("房間已入住!請(qǐng)勿打擾!");

}

}

package com.example.demo.state;

/**

* 方法對(duì)象

*/

public class Context {

// 如果是銀行系統(tǒng),這個(gè)Context類就是賬號(hào).根據(jù)金額不同,切換不同的狀態(tài)!

private State state;

public void setState(State s) {

System.out.println("修改狀態(tài)!");

state = s;

state.handle();

}

}

package com.example.demo.state;

public class Client {

public static void main(String[] args) {

Context context =? new Context();

context.setState(new FreeState());

context.setState(new BookedState());

context.setState(new CheckedInState());

}

}

觀察者模式(Observer) :

核心 :

觀察者模式主要用于1 : N的通知.當(dāng)一個(gè)對(duì)象(目標(biāo)對(duì)象(消息發(fā)布)Subject或Objservable)的狀態(tài)變化時(shí),他需要及時(shí)告知一系列對(duì)象(觀察者對(duì)象(消息訂閱),Observer),令他們做出相應(yīng);

通知觀察者的方式 :

推 : 每次都會(huì)把通知以廣播方式發(fā)送給所有觀察者,所有觀察者只能被動(dòng)接收.

拉 : 觀察者只要直到有情況即可.至于什么時(shí)候獲取內(nèi)容,獲取什么內(nèi)容,都可以自主決定.

例子 :

package com.example.demo.observer;

public interface Observer {

void update(Subject subject);

}

package com.example.demo.observer;

import java.util.ArrayList;

import java.util.List;

public class Subject {

protected List<Observer> list = new ArrayList<>();

public void registerObserver(Observer obs) {

list.add(obs);

}

public void removeObserver(Observer obs) {

list.remove(obs);

}

//通知所有的觀察者更新狀態(tài)

public void notifyAllObservers() {

for (Observer observer : list) {

observer.update(this);

}

}

}

package com.example.demo.observer;

public class ObserverA implements Observer {

// myState需要跟目標(biāo)對(duì)象的state值保存一致!

private int myState;

@Override

public void update(Subject subject) {

myState = ((ConcreteSubject)subject).getState();

}

public int getMyState() {

return myState;

}

public void setMyState(int myState) {

this.myState = myState;

}

}

package com.example.demo.observer;

public class ConcreteSubject extends Subject {

private int state;

public int getState() {

return state;

}

public void setState(int state) {

this.state = state;

// 主題對(duì)象(目標(biāo)對(duì)象)值發(fā)生了變化,請(qǐng)通知所有的觀察者

this.notifyAllObservers();

}

}

package com.example.demo.observer;

public class Client {

public static void main(String[] args) {

// 目標(biāo)對(duì)象

ConcreteSubject subject = new ConcreteSubject();

// 創(chuàng)建多個(gè)觀察者

ObserverA obs1 = new ObserverA();

ObserverA obs2 = new ObserverA();

ObserverA obs3 = new ObserverA();

// 將這三個(gè)觀察者添加到subject對(duì)象的觀察者隊(duì)伍中

subject.registerObserver(obs1);

subject.registerObserver(obs2);

subject.registerObserver(obs3);

// 改變subject的狀態(tài)

subject.setState(3000);

// 我們看看,觀察者的狀態(tài)是不是也發(fā)生了變化

System.out.println(obs1.getMyState());

System.out.println(obs2.getMyState());

System.out.println(obs3.getMyState());

System.out.println("------------------");

// 改變subject的狀態(tài)

subject.setState(30);

// 我們看看,觀察者的狀態(tài)是不是也發(fā)生了變化

System.out.println(obs1.getMyState());

System.out.println(obs2.getMyState());

System.out.println(obs3.getMyState());

}

}

JavaSE提供了java.util.Observable和java.util.Observer來實(shí)現(xiàn)觀察者模式;

例子 :

package com.example.demo.observer2;

import java.util.Observable;

import java.util.Observer;

public class ObserverA implements Observer {

private int myState;

@Override

public void update(Observable o, Object arg) {

myState = ((ConcreteSubject) o).getState();

}

public int getMyState() {

return myState;

}

public void setMyState(int myState) {

this.myState = myState;

}

}

package com.example.demo.observer2;

import java.util.Observable;

public class ConcreteSubject extends Observable {

private int state;

public void set(int a) {

// 目標(biāo)對(duì)象的狀態(tài)發(fā)生了改變

state = a;

// 表示目標(biāo)對(duì)象已經(jīng)做了更改

setChanged();

// 通知所有的觀察者

notifyObservers(state);

}

public int getState() {

return state;

}

public void setState(int state) {

this.state = state;

}

}

package com.example.demo.observer2;

public class Client {

public static void main(String[] args) {

// 創(chuàng)建目標(biāo)對(duì)象Obserable

ConcreteSubject subject = new ConcreteSubject();

// 創(chuàng)建觀察者

ObserverA observerA = new ObserverA();

ObserverA observerA1 = new ObserverA();

ObserverA observerA2 = new ObserverA();

// 將上面三個(gè)觀察者對(duì)象添加到目標(biāo)對(duì)象subject的觀察者容器中

subject.addObserver(observerA);

subject.addObserver(observerA1);

subject.addObserver(observerA2);

// 改變subject對(duì)象的狀態(tài)

subject.set(3000);

System.out.println(observerA.getMyState());

System.out.println(observerA1.getMyState());

System.out.println(observerA2.getMyState());

}

}

開發(fā)中常見的場(chǎng)景 :

聊天室程序的,服務(wù)器轉(zhuǎn)發(fā)給所有客戶端;網(wǎng)絡(luò)游戲(多人聯(lián)機(jī)對(duì)戰(zhàn))場(chǎng)景中,服務(wù)器將客戶端的狀態(tài)進(jìn)行分發(fā);郵件訂閱;Servlet中,監(jiān)聽器的實(shí)現(xiàn);Android中,廣播機(jī)制;

JDK的AWT中事件處理模型,基于觀察者模式的委派事件模型(Delegation Event Model)

事件源 ----- 目標(biāo)對(duì)象

事件監(jiān)聽器 -----觀察者

京東商城中,群發(fā)某商品打折信息

備忘錄模式(memento) :

核心 : 就是保持某個(gè)對(duì)象內(nèi)部狀態(tài)的拷貝,這樣以后就可以將該對(duì)象恢復(fù)到原先的狀態(tài).

結(jié)構(gòu) : 源發(fā)器類Originator;備忘錄類Memento;負(fù)責(zé)人類CarTake.

備忘點(diǎn)較多時(shí) :

將備忘錄壓棧

public class CareTaker {

private Memento memento;

private Stack<Memento> stack = new Stack<Memento>();

}

將多個(gè)備忘錄對(duì)象,序列化和持久化;

開發(fā)中常見的應(yīng)用場(chǎng)景 :

棋類游戲中的,悔棋;普通軟件中的,撤銷操作;數(shù)據(jù)庫(kù)軟件中的,事務(wù)管理中的,回滾操作;Photoshop軟件中的,歷史記錄

例子 :

package com.example.demo.memento;

/**

* 源發(fā)器類

*/

public class Emp {

private String ename;

private int age;

private double salary;

public Emp(String ename, int age, double salary) {

this.ename = ename;

this.age = age;

this.salary = salary;

}

// 進(jìn)行備忘操作,并返回備忘錄對(duì)象

public EmpMemento memento() {

return new EmpMemento(this);

}

// 進(jìn)行數(shù)據(jù)恢復(fù),恢復(fù)成制定備忘錄對(duì)象的值

public void recovery(EmpMemento mmt) {

this.ename = mmt.getEname();

this.age = mmt.getAge();

this.salary = mmt.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 getSalary() {

return salary;

}

public void setSalary(double salary) {

this.salary = salary;

}

}

package com.example.demo.memento;

/**

* 負(fù)責(zé)人類

* 負(fù)責(zé)管理備忘錄對(duì)象

*/

public class CareTaker {

private EmpMemento empMemento;

public EmpMemento getEmpMemento() {

return empMemento;

}

public void setEmpMemento(EmpMemento empMemento) {

this.empMemento = empMemento;

}

}

package com.example.demo.memento;

/**

* 備忘錄類

*/

public class EmpMemento {

private String ename;

private int age;

private double salary;

public EmpMemento(Emp e) {

this.ename = e.getEname();

this.age = e.getAge();

this.salary = e.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 getSalary() {

return salary;

}

public void setSalary(double salary) {

this.salary = salary;

}

}

package com.example.demo.memento;

public class Client {

public static void main(String[] args) {

CareTaker taker = new CareTaker();

Emp emp = new Emp("高琪", 18, 500);

System.out.println("第一打印創(chuàng)建對(duì)象 : " + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary());

// 備忘一次

taker.setEmpMemento(emp.memento());

emp.setAge(38);

emp.setEname("王五");

emp.setSalary(800);

System.out.println("第二次打印創(chuàng)建對(duì)象 : " + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary());

// 恢復(fù)到備忘錄對(duì)象保存的狀態(tài)

emp.recovery(taker.getEmpMemento());

System.out.println("第三次打印創(chuàng)建對(duì)象 : " + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary());

}

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容