1. 程式人生 > >從網咖上網中學習裝飾者模式

從網咖上網中學習裝飾者模式

前言

前面在學習mybatis的二級快取中,我們提到CachingExcuter,以及cache介面中用到了裝飾者設計模式,那麼到底什麼是裝飾者設計模式呢?它有什麼優勢呢?下面結合網咖上網的例子來看看裝飾者模式如何將普通玩家裝飾為人民幣玩家。

裝飾者模式介紹

1.裝飾者類要實現真實類同樣的介面

2.裝飾者類內有一個真實物件的引用(可以通過裝飾者類的構造器傳入)

3.裝飾類物件在主類中接受請求,將請求傳送給真實的物件(相當於已經將引用傳遞到了裝飾類的真實物件)

4.裝飾者可以在傳入真實物件後,增加一些附加功能(因為裝飾物件和真實物件都有同樣的方法,裝飾物件可以新增一定操作在呼叫真實物件的方法,或者先呼叫真實物件的方法,再新增自己的方法)

程式碼展示

package com.aiqinhai;
/*
 * 最原始(diaosi)的網咖上網介面
 * 需要裝飾的原始物件
 */
public interface PlayComputeGame {
	//掏出身份證登記,付錢
	public void ChargeMoney();
	//開啟電腦
	public void turnOnTheComputer();
	//吃雞
	public void eatChicken();
	//整個上網吃雞流程
	public void playComputeGame();
}

上面是需要被裝飾的原始介面,下面展示原始介面的直接實現類

package com.aiqinhai;
/**
 * 佛繫上網(其實是兜裡的錢只夠網費)
 * 需要被裝飾物件的實現類
 * @author aiqinhai
 */
public class PlayComputeGameWithNothing implements PlayComputeGame{

	@Override
	public void ChargeMoney() {
		// TODO Auto-generated method stub
		System.out.println("老闆,充五塊錢網費!");
	}

	@Override
	public void turnOnTheComputer() {
		// TODO Auto-generated method stub
		System.out.println("找個機子,操,隔壁位的小孩德瑪玩的可以嘛!");
	}

	@Override
	public void eatChicken() {
		// TODO Auto-generated method stub
		System.out.println("開始吃雞!");
	}

	@Override
	public void playComputeGame() {
		// TODO Auto-generated method stub
		ChargeMoney();
		turnOnTheComputer();
		eatChicken();
	}
}

上面的上網,只是吃雞,單純的佛繫上網,這時候肚子有點餓咋搞,沒關係,我們有錢,用裝飾者搞定。下面就是裝飾著抽象類

package com.aiqinhai;
/**
 * 裝飾者
 * 用錢裝飾的人民幣玩家
 * @author aiqinhai
 */
public  abstract class PlayComputerGameWithMoney implements PlayComputeGame{
	private final PlayComputeGame playComputeGame;
	
	public PlayComputerGameWithMoney(PlayComputeGame playComputeGame){
		super();
		this.playComputeGame=playComputeGame;
	}
	
	public void ChargeMoney(){
		this.playComputeGame.ChargeMoney();
	}
	
	public void turnOnTheComputer(){
		this.playComputeGame.turnOnTheComputer();
	}
	
	public void eatChicken(){
		this.playComputeGame.eatChicken();
	}
	
	public void playComputeGame(){
		ChargeMoney();
		turnOnTheComputer();
		eatChicken();
	}
}

上面既然有裝飾者了,那麼我想來份熱狗怎麼說

package com.aiqinhai;
/**
 * 吃熱狗版上網
 * @author aiqinhai
 *
 */
public class PlayComputerGameWithHotDog  extends PlayComputerGameWithMoney{

	public PlayComputerGameWithHotDog(PlayComputeGame playComputeGame) {
		super(playComputeGame);
		// TODO Auto-generated constructor stub
	}
	
	public void buyHotDog(){
		System.out.println("網管,來一份熱狗,那個誰同款的!");
	}
	
	public void eatChicken(){
		this.buyHotDog();
		super.eatChicken();
	}
}

有熱狗沒有辣條這種國民美食,怎麼行!

package com.aiqinhai;
/**
 * 吃辣條版本上網
 * @author aiqinhai
 */
public class PlayComputerGameWithLatiao  extends PlayComputerGameWithMoney{

	public PlayComputerGameWithLatiao(PlayComputeGame playComputeGame) {
		super(playComputeGame);
		// TODO Auto-generated constructor stub
	}
	
	public void buyLatiao(){
		System.out.println("網管,來包辣條!");
	}
	
	public void  eatChicken(){
		this.buyLatiao();
		super.eatChicken();
	}
}

接下來看看經過裝飾著裝飾之後的人民幣玩家如何上網

package com.aiqinhai;
/**
 * 開始人民幣玩家上網模式
 * (聽說熱狗和辣條更配哦)
 * @author aiqinhai
 */
public class Client {
	public static void main(String[] args) {
		System.out.println("diaosi玩家裝飾為人民幣玩家");
		PlayComputeGame playComputerGame=new PlayComputeGameWithNothing();
		playComputerGame=new PlayComputerGameWithHotDog(playComputerGame);
		playComputerGame=new PlayComputerGameWithLatiao(playComputerGame);
		playComputerGame.playComputeGame();
		System.out.println("裝飾成功,唉,我這無處安放的魅力啊!");
	}
}

效果如下

上面的上網已經結束了,那麼如果這時候吃辣條口渴了,我想來份可樂咋搞?我們可以在寫個喝可樂上網的類,去繼承裝飾者類,然後再在mian方法中去呼叫就可以了。。當然你還可以來一位陪玩小姐姐啥的,畢竟人民幣玩家嘛!

總結

上面的裝飾者設計模式上網的例子想必大家都懂了,那麼為啥要用裝飾者模式呢?在裝飾者模式之前是怎麼解決的呢?其實如果不適用裝飾者模式,我們採用多次繼承的方式,比如說我想上網的時候吃熱狗,我們就用PlayComputerGameWithHotDog去繼承PlayComputeGameWithNothing,我想上網的時候吃辣條,我們就用PlayComputerGameWithLatiao去繼承PlayComputeGameWithNothing,那如果我想既吃熱狗又吃辣條咋搞,我們可以用PlayComputerGameWithLatiao去繼承已經繼承PlayComputeGameWithNothing的PlayComputerGameWithHotDog類。這樣就可以同時上網吃辣條和熱狗了。但是如果不滿足還想來位陪玩小姐姐,我就又得再繼承。。。這樣下去,這條繼承鏈會變得很長很長,畢竟慾望這東西沒有結束的時候,這樣後期維護起來顯然很費力。所以這時候的裝飾者的優勢就體現出來了。