==目錄==
==前言==
1. 設(shè)計(jì)模式分類
創(chuàng)建型模式:用來(lái)構(gòu)建對(duì)象以便能從實(shí)現(xiàn)系統(tǒng)解耦
結(jié)構(gòu)型模式:用不同的對(duì)象組成大規(guī)模的對(duì)象結(jié)構(gòu)
行為型模式:用來(lái)在對(duì)象中管理算法、關(guān)系、責(zé)任
對(duì)象層面:處理對(duì)象之間的關(guān)系张吉,決定于運(yùn)行期
類層面:處理類的關(guān)系,決定于在編譯器
2. 設(shè)計(jì)模式六大原則
1-開(kāi)閉原則:
對(duì)擴(kuò)展開(kāi)放烹植,對(duì)修改關(guān)閉。
就是代碼需要擴(kuò)展的時(shí)候愕贡,不需要修改原有的代碼草雕。
而實(shí)現(xiàn)開(kāi)閉原則的關(guān)鍵步驟就是抽象化。
2-里氏代換原則:
是對(duì)開(kāi)閉原則的補(bǔ)充固以。
對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范墩虹。
3-依賴倒轉(zhuǎn)原則:
是開(kāi)閉原則的基礎(chǔ)。
針對(duì)接口編程憨琳,依賴抽象而不是具體诫钓。
4-接口隔離原則:
使用多個(gè)隔離的接口,比使用單個(gè)接口要好篙螟。
降低類之間的耦合度菌湃。
5-最小知識(shí)原則:
一個(gè)實(shí)體應(yīng)當(dāng)盡量少地與其他實(shí)體之間發(fā)生相互作用,使得系統(tǒng)功能模塊相對(duì)獨(dú)立
6-合成/聚合復(fù)用原則:
盡量使用合成/聚合的方式遍略,而不是使用繼承
面向?qū)ο笤瓌t:
對(duì)接口編程而不是對(duì)實(shí)現(xiàn)編程惧所。
優(yōu)先使用對(duì)象組合而不是繼承场梆。
==1-行為型==
==1-觀察者模式-行為型==
優(yōu)點(diǎn):
1、觀察者和被觀察者是抽象耦合的纯路。
2、建立一套觸發(fā)機(jī)制寞忿。
缺點(diǎn):
1驰唬、如果一個(gè)被觀察者對(duì)象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會(huì)花費(fèi)很多時(shí)間腔彰。
2叫编、如果在觀察者和觀察目標(biāo)之間有循環(huán)依賴的話,觀察目標(biāo)會(huì)觸發(fā)它們之間進(jìn)行循環(huán)調(diào)用霹抛,可能導(dǎo)致系統(tǒng)崩潰搓逾。
3、觀察者模式?jīng)]有相應(yīng)的機(jī)制讓觀察者知道所觀察的目標(biāo)對(duì)象是怎么發(fā)生變化的杯拐,而僅僅只是知道觀察目標(biāo)發(fā)生了變化霞篡。
使用場(chǎng)景:
1、一個(gè)抽象模型有兩個(gè)方面端逼,其中一個(gè)方面依賴于另一個(gè)方面朗兵。將這些方面封裝在獨(dú)立的對(duì)象中使它們可以各自獨(dú)立地改變和復(fù)用。
2顶滩、一個(gè)對(duì)象的改變將導(dǎo)致其他一個(gè)或多個(gè)對(duì)象也發(fā)生改變余掖,而不知道具體有多少對(duì)象將發(fā)生改變,可以降低對(duì)象之間的耦合度礁鲁。
3盐欺、一個(gè)對(duì)象必須通知其他對(duì)象,而并不知道這些對(duì)象是誰(shuí)仅醇。
4冗美、需要在系統(tǒng)中創(chuàng)建一個(gè)觸發(fā)鏈,A對(duì)象的行為將影響B(tài)對(duì)象着憨,B對(duì)象的行為將影響C對(duì)象……墩衙,可以使用觀察者模式創(chuàng)建一種鏈?zhǔn)接|發(fā)機(jī)制。
1. 創(chuàng)建主題
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. 創(chuàng)建觀察者抽象類
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
3. 創(chuàng)建實(shí)體觀察者類
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() ) );
}
}
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() ) );
}
}
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. 應(yīng)用
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. 執(zhí)行程序甲抖,輸出結(jié)果:
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
==2-模板模式-行為型==
優(yōu)點(diǎn):
1漆改、封裝不變部分,擴(kuò)展可變部分准谚。
2挫剑、提取公共代碼,便于維護(hù)柱衔。
3樊破、行為由父類控制愉棱,子類實(shí)現(xiàn)。
缺點(diǎn):
每一個(gè)不同的實(shí)現(xiàn)都需要一個(gè)子類來(lái)實(shí)現(xiàn)哲戚,導(dǎo)致類的個(gè)數(shù)增加奔滑,使得系統(tǒng)更加龐大。
使用場(chǎng)景:
1顺少、有多個(gè)子類共有的方法朋其,且邏輯相同。
2脆炎、重要的梅猿、復(fù)雜的方法,可以考慮作為模板方法秒裕。
1. 創(chuàng)建模板抽象類
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//模板
public final void play(){
//初始化游戲
initialize();
//開(kāi)始游戲
startPlay();
//結(jié)束游戲
endPlay();
}
}
2. 繼承模板抽象類
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!");
}
}
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. 應(yīng)用
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}
4. 執(zhí)行程序袱蚓,輸出結(jié)果:
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!
==3-策略模式-行為型==
優(yōu)點(diǎn):
1、算法可以自由切換几蜻。
2喇潘、避免使用多重條件判斷。
3梭稚、擴(kuò)展性良好响蓉。
缺點(diǎn):
1、策略類會(huì)增多哨毁。
2枫甲、所有策略類都需要對(duì)外暴露。
使用場(chǎng)景:
1扼褪、如果在一個(gè)系統(tǒng)里面有許多類想幻,它們之間的區(qū)別僅在于它們的行為,那么使用策略模式可以動(dòng)態(tài)地讓一個(gè)對(duì)象在許多行為中選擇一種行為话浇。
2脏毯、一個(gè)系統(tǒng)需要?jiǎng)討B(tài)地在幾種算法中選擇一種。
3幔崖、如果一個(gè)對(duì)象有很多的行為食店,如果不用恰當(dāng)?shù)哪J剑@些行為就只好使用多重的條件選擇語(yǔ)句來(lái)實(shí)現(xiàn)赏寇。
1. 創(chuàng)建接口
public interface Strategy {
public int doOperation(int num1, int num2);
}
2. 創(chuàng)建接口實(shí)現(xiàn)類
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
public class OperationSubstract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
3. 創(chuàng)建Context類, 整合接口和實(shí)現(xiàn)類(擁有接口, 實(shí)現(xiàn)動(dòng)態(tài)方法)
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 來(lái)查看當(dāng)它改變策略 Strategy 時(shí)的行為變化
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. 執(zhí)行程序吉嫩,輸出結(jié)果:
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
==4-責(zé)任鏈模式-行為型==
優(yōu)點(diǎn):
1、降低耦合度嗅定。它將請(qǐng)求的發(fā)送者和接收者解耦自娩。
2、簡(jiǎn)化了對(duì)象渠退。使得對(duì)象不需要知道鏈的結(jié)構(gòu)忙迁。
3脐彩、增強(qiáng)給對(duì)象指派職責(zé)的靈活性。通過(guò)改變鏈內(nèi)的成員或者調(diào)動(dòng)它們的次序姊扔,允許動(dòng)態(tài)地新增或者刪除責(zé)任惠奸。
4、增加新的請(qǐng)求處理類很方便恰梢。
缺點(diǎn):
1晨川、不能保證請(qǐng)求一定被接收。
2删豺、系統(tǒng)性能將受到一定影響,而且在進(jìn)行代碼調(diào)試時(shí)不太方便愧怜,可能會(huì)造成循環(huán)調(diào)用呀页。
3、可能不容易觀察運(yùn)行時(shí)的特征拥坛,有礙于除錯(cuò)蓬蝶。
使用場(chǎng)景:
1、有多個(gè)對(duì)象可以處理同一個(gè)請(qǐng)求猜惋,具體哪個(gè)對(duì)象處理該請(qǐng)求由運(yùn)行時(shí)刻自動(dòng)確定丸氛。
2、在不明確指定接收者的情況下著摔,向多個(gè)對(duì)象中的一個(gè)提交一個(gè)請(qǐng)求缓窜。
3、可動(dòng)態(tài)指定一組對(duì)象處理請(qǐng)求谍咆。
1. 創(chuàng)建抽象的記錄器類禾锤。
public abstract class AbstractLogger {
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
protected int level;
//責(zé)任鏈中的下一個(gè)元素
protected AbstractLogger nextLogger;
public void setNextLogger(AbstractLogger nextLogger){
this.nextLogger = nextLogger;
}
public void logMessage(int level, String message){
if(this.level <= level){
write(message);
}
if(nextLogger !=null){
nextLogger.logMessage(level, message);
}
}
abstract protected void write(String message);
}
2. 創(chuàng)建擴(kuò)展了該記錄器類的實(shí)體類。
public class ConsoleLogger extends AbstractLogger {
public ConsoleLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Standard Console::Logger: " + message);
}
}
public class ErrorLogger extends AbstractLogger {
public ErrorLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Error Console::Logger: " + message);
}
}
public class FileLogger extends AbstractLogger {
public FileLogger(int level){
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("File::Logger: " + message);
}
}
3. 創(chuàng)建不同類型的記錄器摹察。賦予它們不同的錯(cuò)誤級(jí)別恩掷,并在每個(gè)記錄器中設(shè)置下一個(gè)記錄器。每個(gè)記錄器中的下一個(gè)記錄器代表的是鏈的一部分供嚎。
public class ChainPatternDemo {
private static AbstractLogger getChainOfLoggers(){
AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
errorLogger.setNextLogger(fileLogger);
fileLogger.setNextLogger(consoleLogger);
return errorLogger;
}
public static void main(String[] args) {
AbstractLogger loggerChain = getChainOfLoggers();
loggerChain.logMessage(AbstractLogger.INFO,
"This is an information.");
loggerChain.logMessage(AbstractLogger.DEBUG,
"This is an debug level information.");
loggerChain.logMessage(AbstractLogger.ERROR,
"This is an error information.");
}
}
4. 執(zhí)行程序黄娘,輸出結(jié)果:
Standard Console::Logger: This is an information.
File::Logger: This is an debug level information.
Standard Console::Logger: This is an debug level information.
Error Console::Logger: This is an error information.
File::Logger: This is an error information.
Standard Console::Logger: This is an error information.
==5-狀態(tài)模式-行為型==
優(yōu)點(diǎn):
1、封裝了轉(zhuǎn)換規(guī)則克滴。
2逼争、枚舉可能的狀態(tài),在枚舉狀態(tài)之前需要確定狀態(tài)種類劝赔。
3氮凝、將所有與某個(gè)狀態(tài)有關(guān)的行為放到一個(gè)類中,并且可以方便地增加新的狀態(tài)望忆,只需要改變對(duì)象狀態(tài)即可改變對(duì)象的行為罩阵。
4竿秆、允許狀態(tài)轉(zhuǎn)換邏輯與狀態(tài)對(duì)象合成一體,而不是某一個(gè)巨大的條件語(yǔ)句塊稿壁。
5幽钢、可以讓多個(gè)環(huán)境對(duì)象共享一個(gè)狀態(tài)對(duì)象,從而減少系統(tǒng)中對(duì)象的個(gè)數(shù)傅是。
缺點(diǎn):
1匪燕、狀態(tài)模式的使用必然會(huì)增加系統(tǒng)類和對(duì)象的個(gè)數(shù)。
2喧笔、狀態(tài)模式的結(jié)構(gòu)與實(shí)現(xiàn)都較為復(fù)雜帽驯,如果使用不當(dāng)將導(dǎo)致程序結(jié)構(gòu)和代碼的混亂。
3书闸、狀態(tài)模式對(duì)"開(kāi)閉原則"的支持并不太好尼变,對(duì)于可以切換狀態(tài)的狀態(tài)模式,增加新的狀態(tài)類需要修改那些負(fù)責(zé)狀態(tài)轉(zhuǎn)換的源代碼浆劲,否則無(wú)法切換到新增狀態(tài)嫌术,而且修改某個(gè)狀態(tài)類的行為也需修改對(duì)應(yīng)類的源代碼。
使用場(chǎng)景:
1牌借、行為隨狀態(tài)改變而改變的場(chǎng)景度气。
2、條件膨报、分支語(yǔ)句的代替者磷籍。
1. 創(chuàng)建一個(gè)接口。
public interface State {
public void doAction(Context context);
}
2. 創(chuàng)建實(shí)現(xiàn)接口的實(shí)體類现柠。
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";
}
}
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. 創(chuàng)建 Context 類择示。
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 來(lái)查看當(dāng)狀態(tài) State 改變時(shí)的行為變化。
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. 執(zhí)行程序晒旅,輸出結(jié)果:
Player is in start state
Start State
Player is in stop state
Stop State
==6-命令模式-行為型==
優(yōu)點(diǎn):
1栅盲、降低了系統(tǒng)耦合度。
2废恋、新的命令可以很容易添加到系統(tǒng)中去谈秫。
缺點(diǎn):
使用命令模式可能會(huì)導(dǎo)致某些系統(tǒng)有過(guò)多的具體命令類。
使用場(chǎng)景:
1鱼鼓、GUI 中每一個(gè)按鈕都是一條命令拟烫。
2、模擬 CMD迄本。
1. 創(chuàng)建訂單接口
public interface Order {
void execute();
}
2. 創(chuàng)建請(qǐng)求類-股票
public class Stock {
private String name = "ABC";
private int quantity = 10;
public void buy(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] bought");
}
public void sell(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] sold");
}
}
3. 創(chuàng)建訂單實(shí)現(xiàn)類
public class BuyStock implements Order {
private Stock abcStock;
public BuyStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.buy();
}
}
public class SellStock implements Order {
private Stock abcStock;
public SellStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.sell();
}
}
4. 創(chuàng)建命令調(diào)用類-經(jīng)紀(jì)人
public class Broker {
private List<Order> orderList = new ArrayList<Order>();
public void takeOrder(Order order){
orderList.add(order);
}
public void placeOrders(){
for (Order order : orderList) {
order.execute();
}
orderList.clear();
}
}
5. 應(yīng)用
public class CommandPatternDemo {
public static void main(String[] args) {
Stock abcStock = new Stock();
BuyStock buyStockOrder = new BuyStock(abcStock);
SellStock sellStockOrder = new SellStock(abcStock);
Broker broker = new Broker();
broker.takeOrder(buyStockOrder);
broker.takeOrder(sellStockOrder);
broker.placeOrders();
}
}
6. 執(zhí)行程序硕淑,輸出結(jié)果:
Stock [ Name: ABC, Quantity: 10 ] bought
Stock [ Name: ABC, Quantity: 10 ] sold
==2-結(jié)構(gòu)型==
==7-適配器模式-結(jié)構(gòu)型==
優(yōu)點(diǎn):
1、可以讓任何兩個(gè)沒(méi)有關(guān)聯(lián)的類一起運(yùn)行。
2置媳、提高了類的復(fù)用于樟。
3、增加了類的透明度拇囊。
4迂曲、靈活性好
缺點(diǎn):
1、過(guò)多地使用適配器寥袭,會(huì)讓系統(tǒng)非常零亂路捧,不易整體進(jìn)行把握。比如传黄,明明看到調(diào)用的是 A 接口杰扫,其實(shí)內(nèi)部被適配成了 B 接口的實(shí)現(xiàn),一個(gè)系統(tǒng)如果太多出現(xiàn)這種情況膘掰,無(wú)異于一場(chǎng)災(zāi)難章姓。因此如果不是很有必要,可以不使用適配器炭序,而是直接對(duì)系統(tǒng)進(jìn)行重構(gòu)。
2.由于 JAVA 至多繼承一個(gè)類苍日,所以至多只能適配一個(gè)適配者類惭聂,而且目標(biāo)類必須是抽象類。
使用場(chǎng)景:
有動(dòng)機(jī)地修改一個(gè)正常運(yùn)行的系統(tǒng)的接口相恃,這時(shí)應(yīng)該考慮使用適配器模式辜纲。
1. 為媒體播放器和更高級(jí)的媒體播放器創(chuàng)建接口。
public interface MediaPlayer {
public void play(String audioType, String fileName);
}
public interface AdvancedMediaPlayer {
public void playVlc(String fileName);
public void playMp4(String fileName);
}
2. 創(chuàng)建實(shí)現(xiàn)了 AdvancedMediaPlayer 接口的實(shí)體類拦耐。
public class VlcPlayer implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: "+ fileName);
}
@Override
public void playMp4(String fileName) {
//什么也不做
}
}
public class Mp4Player implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
//什么也不做
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: "+ fileName);
}
}
3. 創(chuàng)建實(shí)現(xiàn)了 MediaPlayer 接口的適配器類耕腾。
public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType){
if(audioType.equalsIgnoreCase("vlc") ){
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
}else if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer.playMp4(fileName);
}
}
}
4. 創(chuàng)建實(shí)現(xiàn)了 MediaPlayer 接口的實(shí)體類。
public class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
//播放 mp3 音樂(lè)文件的內(nèi)置支持
if(audioType.equalsIgnoreCase("mp3")){
System.out.println("Playing mp3 file. Name: "+ fileName);
}
//mediaAdapter 提供了播放其他文件格式的支持
else if(audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")){
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else{
System.out.println("Invalid media. "+
audioType + " format not supported");
}
}
}
5. 使用 AudioPlayer 來(lái)播放不同類型的音頻格式杀糯。
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
6. 執(zhí)行程序扫俺,輸出結(jié)果:
Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported
==8-代理模式-結(jié)構(gòu)型==
優(yōu)點(diǎn):
1、職責(zé)清晰固翰。
2狼纬、高擴(kuò)展性。
3骂际、智能化疗琉。
缺點(diǎn):
1、由于在客戶端和真實(shí)主題之間增加了代理對(duì)象歉铝,因此有些類型的代理模式可能會(huì)造成請(qǐng)求的處理速度變慢盈简。
2、實(shí)現(xiàn)代理模式需要額外的工作,有些代理模式的實(shí)現(xiàn)非常復(fù)雜柠贤。
使用場(chǎng)景:
1香浩、遠(yuǎn)程代理。
2种吸、虛擬代理弃衍。
3、Copy-on-Write 代理坚俗。
4镜盯、保護(hù)(Protect or Access)代理。
5猖败、Cache代理速缆。
6、防火墻(Firewall)代理恩闻。
7艺糜、同步化(Synchronization)代理。
8幢尚、智能引用(Smart Reference)代理破停。
1. 創(chuàng)建一個(gè)接口。
public interface Image {
void display();
}
2. 創(chuàng)建實(shí)現(xiàn)接口的實(shí)體類尉剩。
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName){
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("Displaying " + fileName);
}
private void loadFromDisk(String fileName){
System.out.println("Loading " + fileName);
}
}
public class ProxyImage implements Image{
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName){
this.fileName = fileName;
}
@Override
public void display() {
if(realImage == null){
realImage = new RealImage(fileName);
}
realImage.display();
}
}
3. 當(dāng)被請(qǐng)求時(shí)真慢,使用 ProxyImage 來(lái)獲取 RealImage 類的對(duì)象。
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test_10mb.jpg");
// 圖像將從磁盤(pán)加載
image.display();
System.out.println("");
// 圖像不需要從磁盤(pán)加載
image.display();
}
}
4. 執(zhí)行程序理茎,輸出結(jié)果:
Loading test_10mb.jpg
Displaying test_10mb.jpg
Displaying test_10mb.jpg
==9-裝飾器模式-結(jié)構(gòu)型==
優(yōu)點(diǎn):
裝飾類和被裝飾類可以獨(dú)立發(fā)展黑界,不會(huì)相互耦合,裝飾模式是繼承的一個(gè)替代模式皂林,裝飾模式可以動(dòng)態(tài)擴(kuò)展一個(gè)實(shí)現(xiàn)類的功能朗鸠。
缺點(diǎn):
多層裝飾比較復(fù)雜。
使用場(chǎng)景:
1础倍、擴(kuò)展一個(gè)類的功能烛占。
2、動(dòng)態(tài)增加功能沟启,動(dòng)態(tài)撤銷扰楼。
1. 創(chuàng)建 Shape 接口
public interface Shape {
void draw();
}
2. 實(shí)現(xiàn)接口
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
3. 創(chuàng)建實(shí)現(xiàn)了 Shape 接口的 抽象裝飾類
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
4. 創(chuàng)建擴(kuò)展了 ShapeDecorator 類的 實(shí)體裝飾類
public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}
5. 使用 RedShapeDecorator 來(lái)裝飾 Shape 對(duì)象
public class DecoratorPatternDemo {
public static void main(String[] args) {
Shape circle = new Circle();
Shape redCircle = new RedShapeDecorator(new Circle());
Shape redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border");
circle.draw();
System.out.println("\nCircle of red border");
redCircle.draw();
System.out.println("\nRectangle of red border");
redRectangle.draw();
}
}
6. 執(zhí)行程序,輸出結(jié)果:
Circle with normal border
Shape: Circle
Circle of red border
Shape: Circle
Border Color: Red
Rectangle of red border
Shape: Rectangle
Border Color: Red
==10-組合模式-結(jié)構(gòu)型==
優(yōu)點(diǎn):
1美浦、高層模塊調(diào)用簡(jiǎn)單弦赖。
2、節(jié)點(diǎn)自由增加浦辨。
缺點(diǎn):
在使用組合模式時(shí)蹬竖,其葉子和樹(shù)枝的聲明都是實(shí)現(xiàn)類沼沈,而不是接口,違反了依賴倒置原則币厕。
使用場(chǎng)景:
部分列另、整體場(chǎng)景,如樹(shù)形菜單旦装,文件页衙、文件夾的管理。
1. 創(chuàng)建 Employee 類阴绢,該類帶有 Employee 對(duì)象的列表店乐。
public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates;
//構(gòu)造函數(shù)
public Employee(String name,String dept, int sal) {
this.name = name;
this.dept = dept;
this.salary = sal;
subordinates = new ArrayList<Employee>();
}
public void add(Employee e) {
subordinates.add(e);
}
public void remove(Employee e) {
subordinates.remove(e);
}
public List<Employee> getSubordinates(){
return subordinates;
}
public String toString(){
return ("Employee :[ Name : "+ name
+", dept : "+ dept + ", salary :"
+ salary+" ]");
}
}
2. 使用 Employee 類來(lái)創(chuàng)建和打印員工的層次結(jié)構(gòu)。
public class CompositePatternDemo {
public static void main(String[] args) {
Employee CEO = new Employee("John","CEO", 30000);
Employee headSales = new Employee("Robert","Head Sales", 20000);
Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
Employee clerk1 = new Employee("Laura","Marketing", 10000);
Employee clerk2 = new Employee("Bob","Marketing", 10000);
Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
CEO.add(headSales);
CEO.add(headMarketing);
headSales.add(salesExecutive1);
headSales.add(salesExecutive2);
headMarketing.add(clerk1);
headMarketing.add(clerk2);
//打印該組織的所有員工
System.out.println(CEO);
for (Employee headEmployee : CEO.getSubordinates()) {
System.out.println(headEmployee);
for (Employee employee : headEmployee.getSubordinates()) {
System.out.println(employee);
}
}
}
}
3. 執(zhí)行程序呻袭,輸出結(jié)果為:
Employee :[ Name : John, dept : CEO, salary :30000 ]
Employee :[ Name : Robert, dept : Head Sales, salary :20000 ]
Employee :[ Name : Richard, dept : Sales, salary :10000 ]
Employee :[ Name : Rob, dept : Sales, salary :10000 ]
Employee :[ Name : Michel, dept : Head Marketing, salary :20000 ]
Employee :[ Name : Laura, dept : Marketing, salary :10000 ]
Employee :[ Name : Bob, dept : Marketing, salary :10000 ]
==11-外觀模式-結(jié)構(gòu)型==
優(yōu)點(diǎn):
1眨八、減少系統(tǒng)相互依賴。
2左电、提高靈活性廉侧。
3、提高了安全性篓足。
缺點(diǎn):
不符合開(kāi)閉原則段誊,如果要改東西很麻煩,繼承重寫(xiě)都不合適栈拖。
使用場(chǎng)景:
1连舍、為復(fù)雜的模塊或子系統(tǒng)提供外界訪問(wèn)的模塊。
2辱魁、子系統(tǒng)相對(duì)獨(dú)立烟瞧。
3诗鸭、預(yù)防低水平人員帶來(lái)的風(fēng)險(xiǎn)疫粥。
1. 創(chuàng)建一個(gè)接口纵潦。
public interface Shape {
void draw();
}
2. 創(chuàng)建實(shí)現(xiàn)接口的實(shí)體類。
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Rectangle::draw()");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Square::draw()");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle::draw()");
}
}
3. 創(chuàng)建一個(gè)外觀類。
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
private Shape square;
public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}
public void drawCircle(){
circle.draw();
}
public void drawRectangle(){
rectangle.draw();
}
public void drawSquare(){
square.draw();
}
}
4. 使用該外觀類畫(huà)出各種類型的形狀逢慌。
public class FacadePatternDemo {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
}
5. 執(zhí)行程序,輸出結(jié)果:
Circle::draw()
Rectangle::draw()
Square::draw()
==3-創(chuàng)建型==
==12-單例模式-創(chuàng)建型==
優(yōu)點(diǎn):
1魁巩、在內(nèi)存里只有一個(gè)實(shí)例牺汤,減少了內(nèi)存的開(kāi)銷,尤其是頻繁的創(chuàng)建和銷毀實(shí)例(比如管理學(xué)院首頁(yè)頁(yè)面緩存)妓盲。
2杂拨、避免對(duì)資源的多重占用(比如寫(xiě)文件操作)。
缺點(diǎn):
沒(méi)有接口悯衬,不能繼承弹沽,與單一職責(zé)原則沖突,一個(gè)類應(yīng)該只關(guān)心內(nèi)部邏輯,而不關(guān)心外面怎么樣來(lái)實(shí)例化策橘。
使用場(chǎng)景:
1炸渡、要求生產(chǎn)唯一序列號(hào)。
2丽已、WEB 中的計(jì)數(shù)器蚌堵,不用每次刷新都在數(shù)據(jù)庫(kù)里加一次,用單例先緩存起來(lái)沛婴。
3吼畏、創(chuàng)建的一個(gè)對(duì)象需要消耗的資源過(guò)多,比如 I/O 與數(shù)據(jù)庫(kù)的連接等瘸味。
12.1 靜態(tài)內(nèi)部類(static inner class)
是否 Lazy 初始化:是
是否多線程安全:是
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
12.2 雙檢鎖/雙重校驗(yàn)鎖(DCL, double-checked locking)
是否 Lazy 初始化:是
是否多線程安全:是
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
==13-工廠模式-創(chuàng)建型==
13.1 簡(jiǎn)單工廠
優(yōu)點(diǎn):
1宫仗、一個(gè)調(diào)用者想創(chuàng)建一個(gè)對(duì)象,只要知道其名稱就可以了旁仿。
2藕夫、擴(kuò)展性高,如果想增加一個(gè)產(chǎn)品枯冈,只要擴(kuò)展一個(gè)工廠類就可以毅贮。
3、屏蔽產(chǎn)品的具體實(shí)現(xiàn)尘奏,調(diào)用者只關(guān)心產(chǎn)品的接口滩褥。
缺點(diǎn):
每次增加一個(gè)產(chǎn)品時(shí),都需要增加一個(gè)具體類和對(duì)象實(shí)現(xiàn)工廠炫加,使得系統(tǒng)中類的個(gè)數(shù)成倍增加瑰煎,在一定程度上增加了系統(tǒng)的復(fù)雜度,同時(shí)也增加了系統(tǒng)具體類的依賴俗孝。這并不是什么好事酒甸。
使用場(chǎng)景:
1、日志記錄器:記錄可能記錄到本地硬盤(pán)赋铝、系統(tǒng)事件插勤、遠(yuǎn)程服務(wù)器等,用戶可以選擇記錄日志到什么地方革骨。
2农尖、數(shù)據(jù)庫(kù)訪問(wèn),當(dāng)用戶不知道最后系統(tǒng)采用哪一類數(shù)據(jù)庫(kù)良哲,以及數(shù)據(jù)庫(kù)可能有變化時(shí)盛卡。
3、設(shè)計(jì)一個(gè)連接服務(wù)器的框架筑凫,需要三個(gè)協(xié)議滑沧,"POP3"喇颁、"IMAP"、"HTTP"嚎货,可以把這三個(gè)作為產(chǎn)品類橘霎,共同實(shí)現(xiàn)一個(gè)接口。
1. 創(chuàng)建一個(gè)接口
public interface Shape {
void draw();
}
2. 創(chuàng)建實(shí)現(xiàn)接口的實(shí)體類殖属。
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
3. 創(chuàng)建一個(gè)工廠姐叁,生成基于給定信息的實(shí)體類的對(duì)象。
public class ShapeFactory {
//使用 getShape 方法獲取形狀類型的對(duì)象
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
4. 使用該工廠洗显,通過(guò)傳遞類型信息來(lái)獲取實(shí)體類的對(duì)象外潜。
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
//獲取 Circle 的對(duì)象,并調(diào)用它的 draw 方法
Shape shape1 = shapeFactory.getShape("CIRCLE");
//調(diào)用 Circle 的 draw 方法
shape1.draw();
//獲取 Rectangle 的對(duì)象挠唆,并調(diào)用它的 draw 方法
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//調(diào)用 Rectangle 的 draw 方法
shape2.draw();
//獲取 Square 的對(duì)象处窥,并調(diào)用它的 draw 方法
Shape shape3 = shapeFactory.getShape("SQUARE");
//調(diào)用 Square 的 draw 方法
shape3.draw();
}
}
5. 執(zhí)行程序,輸出結(jié)果
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
13.2 抽象工廠
優(yōu)點(diǎn):
當(dāng)一個(gè)產(chǎn)品族中的多個(gè)對(duì)象被設(shè)計(jì)成一起工作時(shí)玄组,它能保證客戶端始終只使用同一個(gè)產(chǎn)品族中的對(duì)象滔驾。
缺點(diǎn):
產(chǎn)品族擴(kuò)展非常困難,要增加一個(gè)系列的某一產(chǎn)品俄讹,既要在抽象的 Creator 里加代碼哆致,又要在具體的里面加代碼。
使用場(chǎng)景:
1患膛、QQ 換皮膚摊阀,一整套一起換。
2踪蹬、生成不同操作系統(tǒng)的程序胞此。
1. 為形狀創(chuàng)建一個(gè)接口。
public interface Shape {
void draw();
}
2. 創(chuàng)建實(shí)現(xiàn)接口的實(shí)體類跃捣。
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
3. 為顏色創(chuàng)建一個(gè)接口漱牵。
public interface Color {
void fill();
}
4. 創(chuàng)建實(shí)現(xiàn)接口的實(shí)體類。
public class Red implements Color {
@Override
public void fill() {
System.out.println("Inside Red::fill() method.");
}
}
public class Green implements Color {
@Override
public void fill() {
System.out.println("Inside Green::fill() method.");
}
}
public class Blue implements Color {
@Override
public void fill() {
System.out.println("Inside Blue::fill() method.");
}
}
5. 為 Color 和 Shape 對(duì)象創(chuàng)建抽象類來(lái)獲取工廠枝缔。
public abstract class AbstractFactory {
public abstract Color getColor(String color);
public abstract Shape getShape(String shape) ;
}
6. 創(chuàng)建擴(kuò)展了 AbstractFactory 的工廠類布疙,基于給定的信息生成實(shí)體類的對(duì)象蚊惯。
public class ShapeFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
@Override
public Color getColor(String color) {
return null;
}
}
public class ColorFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
return null;
}
@Override
public Color getColor(String color) {
if(color == null){
return null;
}
if(color.equalsIgnoreCase("RED")){
return new Red();
} else if(color.equalsIgnoreCase("GREEN")){
return new Green();
} else if(color.equalsIgnoreCase("BLUE")){
return new Blue();
}
return null;
}
}
7. 創(chuàng)建一個(gè)工廠創(chuàng)造器/生成器類愿卸,通過(guò)傳遞形狀或顏色信息來(lái)獲取工廠截型。
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
8. 使用 FactoryProducer 來(lái)獲取 AbstractFactory,通過(guò)傳遞類型信息來(lái)獲取實(shí)體類的對(duì)象宦焦。
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
//獲取形狀工廠
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
//獲取形狀為 Circle 的對(duì)象
Shape shape1 = shapeFactory.getShape("CIRCLE");
//調(diào)用 Circle 的 draw 方法
shape1.draw();
//獲取形狀為 Rectangle 的對(duì)象
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//調(diào)用 Rectangle 的 draw 方法
shape2.draw();
//獲取形狀為 Square 的對(duì)象
Shape shape3 = shapeFactory.getShape("SQUARE");
//調(diào)用 Square 的 draw 方法
shape3.draw();
//獲取顏色工廠
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
//獲取顏色為 Red 的對(duì)象
Color color1 = colorFactory.getColor("RED");
//調(diào)用 Red 的 fill 方法
color1.fill();
//獲取顏色為 Green 的對(duì)象
Color color2 = colorFactory.getColor("Green");
//調(diào)用 Green 的 fill 方法
color2.fill();
//獲取顏色為 Blue 的對(duì)象
Color color3 = colorFactory.getColor("BLUE");
//調(diào)用 Blue 的 fill 方法
color3.fill();
}
}
9. 執(zhí)行程序顿涣,輸出結(jié)果:
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.