1. 程式人生 > >GO BEYOND YOURSELF

GO BEYOND YOURSELF

              學過面向物件的我們都知道,通過繼承:能夠重用和擴充套件已經被徹底測試過的程式碼,且無需修改之。但就像策略模式中所講到的,繼承會禁錮類的方法。那麼如果要擴充套件功能,我們還是必須使用繼承嗎?

              答案當然是否定的,因為設計模式中為我們提供了一個很好的模式--裝飾模式:動態地將責任附加到物件上。這裡所謂的動態可以簡單理解為靈活。那麼不使用繼承,又要如何幫助我們達到目的呢?下面一起來看。

             先來看一個例子,我們去咖啡店買咖啡,光咖啡型別就有不同的選擇:綜合、深焙、低咖啡因、濃縮。但喝咖啡可沒這麼簡單,它還需要加入相應的配料來滿足顧客口味需求:牛奶、豆漿、摩卡、奶泡。現在咖啡店要增加一些新口味和型別,那麼原先使用繼承的系統將不再適用,一旦增加的型別和種類增多下面的這張圖就變成一坨了吧:

       

         那麼使用裝飾模式應該是什麼樣的呢?

         

            像上面這幅圖顯示的這樣,我們將具體的咖啡型別和配料都作為一個類的子類,通過型別和配料的自由組合實現功能的同時實現程式碼的複用性,提高後期的可維護性。其程式碼如下: 

1.抽象類

<span style="font-size:18px;">package 巴茲咖啡;
//這是一個抽象類。
public abstract class Beverage {
	String description ="Unknown Beverage";
	
	public String getDescription (){
		//獲取咖啡調配方法
		return description;
	}
	
	public abstract double cost();
}
</span>


2.具體元件

public abstract class CondimentDecorator extends Beverage {
	public abstract String getDescription();
}

public class DarkRoast extends Beverage {

	public DarkRoast() {
		description ="DarkRoast Coffee";   
	}
	
	public double cost(){
		return .99;
	}

}
</span>
public class Espresso extends Beverage {
	
	public Espresso ()
	{
		description ="Espresso";
	}
	
	public double cost(){
		return 1.99;
	}
}
public class HouseBlend extends Beverage {
	public HouseBlend(){
		description ="House Blend Coffee";
	}
	
	public double cost(){
		return .89;
	}
}
</span>

          其他幾個類和上面列舉的類似,大家可以動手實現。最終會實現下面的效果:

        

            如果店內有需求,要實現杯型大小來進行收費,那麼我們可以在CondimentDecorator中新增中杯、小杯、大杯三個類,抽象類中新增方法:getSize()對杯型進行獲取,然後通過杯型、咖啡型別和配料的不同搭配來實現靈活收費。這樣一來也就實現了動態的新增的同時也達到了解耦的效用。豈不是一舉兩得?

總結:

 1.裝飾模式中使用組合和委託在系統執行時對系統動態的增加功能。而該模式也就意味著我們要建立一堆的裝飾者類,而它們又恰好是用來裝飾元件的,比如:Mocha、Whip等四個配料都是用來裝飾HouseBlend、 DarkRoast這 些咖啡型別的。

2.我們可以使用一個或者多個裝飾者包裝一個元件:調配出一箇中杯的,加入牛奶、摩卡等的低咖啡因咖啡。

3.裝飾者會導致設計中出現許多小物件,如果過度使用,程式依舊會變得複雜。也就是說,我們不能將咖啡的型別和配料的種類無限的擴張,否則系統會因為過多的咖啡種類和配料而執行緩慢甚至癱瘓。凡事遵循一度的問題,東西再好吃也不能撐死,模式再好用也不能拖死系統。

所以說,在一定程度上,裝飾者模式還是很棒的呢。

            最後祝大家軟考順利,考試加油,let's  go !!

相關推薦

GO BEYOND YOURSELF

              學過面向物件的我們都知道,通過繼承:能夠重用和擴充套件已經被徹底測試過的程式碼,且無需修改之。但就像策略模式中所講到的,繼承會禁錮類的方法。那麼如果要擴充套件功能,我們還是

Be yourself and Beyond yourself

傳統的開發團隊通常按角色就行分工, 開發人員只管開發, 測試人員只管測試, 在自己的職責之外的事, 要麼是看不見, 要麼是覺得不是我的活,我不用去管,做好做壞和我沒有關係。 而敏捷軟體開發恰恰相反, 更加強調“Whole Team”, 即整個團隊對外做出承諾, 團隊中的所

No one can go beyond

大多數人認為的Linux系統安裝軟體都比較麻煩,Linux系統的軟體也非常少,其實不然,Ubuntu發行版的Linux安裝軟體非常簡單,軟體應用也非常多,今天小編就給大家分享Ubuntu系統中如何安裝軟體。 我們就以安裝Chrome瀏覽器為例來說明如何在Ubuntu系統中安裝Chrome瀏覽器。

How to go from a Blockchain Tourist to a Blockchain Citizen: Beyond the Hype

How to go from a Blockchain Tourist to a Blockchain Citizen: Beyond the HypeHow to go from a Blockchain Tourist to a Blockchain CitizenBlockchain tourism a

go 自己封的postgresql操作包

rep make query res urn mod .exe errors exe 1 package myDB 2 3 import ( 4 "database/sql" 5 "errors" 6 7 _ "g

go-005-變量

整數 func 基礎 字型 開始 import open spl 註意 概述   變量來源於數學,是計算機語言中能儲存計算結果或能表示值抽象概念。變量可以通過變量名訪問。   Go 語言變量名由字母、數字、下劃線組成,其中首個字母不能為數字。   聲明變量的一般形式是

GO中常用包筆記 bytes(四)

g 學習筆記 bytes包Package bytes對字節數組進行操作的包。功能和strings包相似.bytes包提供的功能有:和另一個字節數組切片的關系(逐字節比較大小,是否相等/相似,是否包含/包含次數,位置搜索,是否是前綴後綴)2.字節數組切片和字符串的關系(字符串中是否含有字節數組所包含的rune,

CDOJ 1221 Ancient Go

cout#include<bits/stdc++.h>using namespace std;bool ok;char maze[15][15];char Map[12][12];bool vis[15][15];int x[4] = {0,0,1,-1};int y[4] = {1,-1,0,0

Go - 數組

索引 創建 16px class 表示 int32 部分 func amp 數組: Array 1. 定義: var <arrayName> [n] (n>=0) <type> 註: 數組的長度n,也是數組定義的組成部分;所以:var i

Go語言之嵌入類型

go 類型 嵌入類型,或者嵌套類型,這是一種可以把已有的類型聲明在新的類型裏的一種方式,這種功能對代碼復用非常重要。在其他語言中,有繼承可以做同樣的事情,但是在Go語言中,沒有繼承的概念。Go提倡的代碼復用的方式是組合,所以這也是嵌入類型的意義所在。組合而不是繼承,所以Go才會更靈活。type Rea

後端程序員之路 52、A Tour of Go-2

run arrays primes var auto 程序 pointer ase tex # flowcontrol - for - for i := 0; i < 10; i++ { - for ; sum < 1000;

go語言的優點

程序編寫 執行文件 語言培訓 多線程 老男孩 老男孩教育go語言培訓是國內首家go語言培訓機構,主講老師是小米架構資深架構師,有多年go開發經驗。小編現將go語言優點整理如下,希望能幫到你們 1.部署簡單Go 編譯生成的是一個靜態可執行文件,除了 glibc 外沒有其他外部依賴。這讓部署變

Go - 切片(Slice)

什麽 部分 pri 長度 code ron logs 內存 tro 定義 切片本身不是數組,它指向底層的數組或者數組的一部分。因此,可以使用Slice來處理變長數組的應用場景。 Silice 是一種引用類型。 1、定義一個空的Slice package main

JavaScript ,Python,java,Go系列算法之選擇排序

javascript java python go系列算法之選擇排序 常見的內部排序算法有:插入排序、希爾排序、選擇排序、冒泡排序、歸並排序、快速排序、堆排序、基數排序等。用一張圖概括:選擇排序 選擇排序是一種簡單直觀的排序算法,無論什麽數據進去都是O(n2) 的時間復雜度。所以用到它的

Go -- log4go日誌

全部 導入 ren tle ack stat body utm app 折騰: 【已解決】go語言中實現log信息同時輸出到文件和控制臺(命令行) 期間,已經通過io的MultiWriter搞定了同時輸出信息到文件和console,但是不支持level。 所以,再去試

Go的微服務庫kite

targe post 服務 core 調用 protocol tag 運行 interface Kite Kite是用Go開發的一套RPC庫,很適合作為分布式微服務的開發框架。 Kite 的傳輸層使用 SockJS 提供的WebSocket服務, 瀏覽器Javascri

go語言筆記——append是內置的函數!!!new是一個函數!!!調試可以使用閉包,本質上是print調試,尼瑪!

... -c map blob 名稱 ebo bsp 處理機制 它的 內置函數 Go 語言擁有一些不需要進行導入操作就可以使用的內置函數。它們有時可以針對不同的類型進行操作,例如:len、cap 和 append,或必須用於系統級的操作,例如:panic。因此,它們需要直接

go語言筆記——切片函數常見操作,增刪改查和搜索、排序

通過 學習 strings 完整 官方文檔 二分 func fun 必須 7.6.6 搜索及排序切片和數組 標準庫提供了 sort 包來實現常見的搜索和排序操作。您可以使用 sort 包中的函數 func Ints(a []int) 來實現對 int 類型的切片排序。例如

go語言筆記——map map 默認是無序的,不管是按照 key 還是按照 value 默認都不排序

pcr 錯誤 固定 pre text 輸出結果 示例 operation frequency 示例 8.1 make_maps.go package main import "fmt" func main() { var mapLit map[string]int

GO語言 --socket.io

broadcast logfile hub println ogg sta out his ror socket.io是對websocket的封裝以及擴展, 可以跨平臺使用, 具體可看官網.. GO語言實現: package main import (