概述
若你從事過(guò)面向?qū)ο箝_(kāi)發(fā),實(shí)現(xiàn)給一個(gè)類(lèi)或?qū)ο笤黾有袨?,使用繼承機(jī)制,這是所有面向?qū)ο笳Z(yǔ)言的一 個(gè)基本特性。如果已經(jīng)存在的一個(gè)類(lèi)缺少某些方法,或者須要給方法添加更多的功能(魅力),你也許會(huì)僅僅繼承這個(gè)類(lèi)來(lái)產(chǎn)生一個(gè)新類(lèi)—這建立在額外的代碼上。
通過(guò)繼承一個(gè)現(xiàn)有類(lèi)可以使得子類(lèi)在擁有自身方法的同時(shí)還擁有父類(lèi)的方法。但是這種方法是靜態(tài)的,用戶(hù)不能控制增加行為的方式和時(shí)機(jī)。如果 你希望改變一個(gè)已經(jīng)初始化的對(duì)象的行為,你怎么辦?或者,你希望繼承許多類(lèi)的行為,改怎么辦?前一個(gè),只能在于運(yùn)行時(shí)完成,后者顯然時(shí)可能的,但是可能會(huì)導(dǎo)致產(chǎn)生大量的不同的類(lèi)—可怕的事情。
問(wèn)題
你如何組織你的代碼使其可以容易的添加基本的或者一些很少用到的 特性,而不是直接不額外的代碼寫(xiě)在你的類(lèi)的內(nèi)部?
解決方案
- 動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)或者行為。就增加功能來(lái)說(shuō), Decorator模式相比生成子類(lèi)更為靈活。
- 提供了改變子類(lèi)的靈活方案。裝飾器模式在不必改變?cè)?lèi)文件和使用繼承的情況下,動(dòng)態(tài)的擴(kuò)展一個(gè)對(duì)象的功能。它是通過(guò)創(chuàng)建一個(gè)包裝對(duì)象,也就是裝飾來(lái)包裹真實(shí)的對(duì)象。
- 當(dāng)用于一組子類(lèi)時(shí),裝飾器模式更加有用。如果你擁有一族子類(lèi)(從一個(gè)父類(lèi)派生而來(lái)),你需要在與子類(lèi)獨(dú)立使用情況下添加額外的特性,你可以使用裝飾器模式,以避免代碼重復(fù)和具體子類(lèi)數(shù)量的增加。
適用性
以下情況使用Decorator模式
- 在不影響其他對(duì)象的情況下,以動(dòng)態(tài)、透明的方式給單個(gè)對(duì)象添加職責(zé)。
- 處理那些可以撤消的職責(zé)。
- 當(dāng)不能采用生成子類(lèi)的方法進(jìn)行擴(kuò)充時(shí)。一種情況是,可能有大量獨(dú)立的擴(kuò)展,
為支持每一種組合將產(chǎn)生大量的子類(lèi),使得子類(lèi)數(shù)目呈爆炸性增長(zhǎng)。
另一種情況可能是因?yàn)轭?lèi)定義被隱藏,或類(lèi)定義不能用于生成子類(lèi)。
實(shí)例
class SimpleWriter
def initialize(path)
@file = File.open(path,"w")
end
def write_line(line)
@file.print(line)
@file.print("\n")
end
#字符數(shù)
def pos
@file.pos
end
#它將會(huì)將文件指針指向文件的開(kāi)頭
def rewind
@file.rewind
end
def close
@file.colse
end
end
sw = SimpleWriter.new("test.txt")
sw.write_line("你好")
puts sw.pos
puts sw.rewind
#基類(lèi)
class WriterDecorator
def initialize(real_writer)
@real_writer = real_writer
end
def write_line
@real_writer.write_line
end
def pos
@real_writer.pos
end
def rewind
@real_writer.rewind
end
def close
@real_writer.close
end
end
class NumberingWriter WriterDecorator
attr :line_number
def initialize(real_writer)
super(real_writer)
@line_number = 1
end
#實(shí)際調(diào)用的是WriterDecorator的write_line方法,只是在寫(xiě)入的內(nèi)容前加上了編號(hào)(裝飾)
#所以說(shuō)NumberingWriter對(duì)WriterDecorator的接口wirte_line進(jìn)行了裝飾
#
def write_line(line)
@real_writer.write_line("#{@line_number}:#{line}")
@line_number += 1
end
end
sw = SimpleWriter.new("numbering_write.txt")
nw = NumberingWriter.new(sw)
nw.write_line("hello,world")
nw.write_line("hello,ruby")
puts nw.line_number
class CheckSummingWriter WriterDecorator
attr_reader :check_num
def initialize(real_writer)
super(real_writer)
@check_num = 0
end
def write_line(line)
line.each_byte{|byte| @check_num += byte % 256}
@real_writer.write_line(line)
end
end
sw = SimpleWriter.new("check_num_writer.txt")
csw = CheckSummingWriter.new(sw)
csw.write_line("hello,world")
puts csw.check_num
class TimeStampingWriter WriterDecorator
def initialize(real_writer)
super(real_writer)
end
def write_line(line)
@real_writer.write_line("#{Time.now}: #{line}")
end
end
#倒著看
#5. 實(shí)際調(diào)用的是SimpleWriter得write_line方法,將內(nèi)容寫(xiě)入文件
sw = SimpleWriter.new("mix.txt")
#4. 實(shí)際調(diào)用的是NumberingWriter得write_line方法,對(duì)在輸入的數(shù)據(jù)前加上了編號(hào)
# 然后傳給@real_writer,此時(shí)的@real_witer為sw
nw = NumberingWriter.new(sw)
#3. 實(shí)際調(diào)用的是TimeStampingWriter得write_line方法,對(duì)在輸入的數(shù)據(jù)前加上了時(shí)間戳
# 然后傳給@real_writer,此時(shí)的@real_witer為nw
tsw = TimeStampingWriter.new(nw)
#2. 實(shí)際調(diào)用的是CheckSummingWriter得write_line方法,對(duì)輸入的數(shù)據(jù)進(jìn)行了字節(jié)數(shù)的統(tǒng)計(jì)
# 然后傳給@real_writer,此時(shí)的@real_witer為tsw
csw = CheckSummingWriter.new(tsw)
#1. csw調(diào)用write_line
csw.write_line("hello,world")
puts csw.check_num
兩種ruby風(fēng)格的裝飾模式應(yīng)用
(1)使用extend混入模塊
class SimpleWriter
def initialize(path)
@file = File.open(path,"w")
end
def write_line(line)
@file.print(line)
@file.print("\n")
end
#字符數(shù)
def pos
@file.pos
end
#它將會(huì)將文件指針指向文件的開(kāi)頭
def rewind
@file.rewind
end
def close
@file.colse
end
end
#使用extend方法動(dòng)態(tài)的混入模塊,來(lái)進(jìn)行裝飾
module TimeStampingWriter
def write_line(line)
super("#{Time.now}:#{line}")
end
end
module NumberingWriter
attr_reader :line_number
def write_line(line)
@line_number = 1 unless @line_number
super("#{@line_number}:#{line}")
@line_number += 1
end
end
最后被加入的模塊,先被調(diào)用,然后通過(guò)super來(lái)調(diào)用父類(lèi)的write_line方法。
例子中先在文本的前面加上時(shí)間戳,在加入編號(hào),最后寫(xiě)入文件
sw = SimpleWriter.new("out3.txt")
sw.extend(NumberingWriter)
sw.extend(TimeStampingWriter)
sw.write_line("hello,ruby")
(2)使用alias關(guān)鍵字
class SimpleWriter
def initialize(path)
@file = File.open(path,"w")
end
def write_line(line)
@file.print(line)
@file.print("\n")
end
#字符數(shù)
def pos
@file.pos
end
#它將會(huì)將文件指針指向文件的開(kāi)頭
def rewind
@file.rewind
end
def close
@file.colse
end
end
ruby實(shí)現(xiàn)裝飾模式的另一種動(dòng)態(tài)方法 :
修改對(duì)象的實(shí)例方法, 所以在out1.txt文件中會(huì)加入時(shí)間戳,而不影響對(duì)象sw2,out2.txt中不會(huì)加入時(shí)間戳 。
sw1 = SimpleWriter.new("out1.txt")
class sw1
alias old_write_line write_line
def write_line(line)
old_write_line("#{Time.now}:#{line}")
end
end
sw1.write_line("hello,world")
sw2 = SimpleWriter.new("out2.txt")
sw2.write_line("hello,world")
您可能感興趣的文章:- 深入解析設(shè)計(jì)模式中的裝飾器模式在iOS應(yīng)用開(kāi)發(fā)中的實(shí)現(xiàn)
- 分析Python中設(shè)計(jì)模式之Decorator裝飾器模式的要點(diǎn)
- 學(xué)習(xí)php設(shè)計(jì)模式 php實(shí)現(xiàn)裝飾器模式(decorator)
- Python的裝飾器模式與面向切面編程詳解
- PHP、Python和Javascript的裝飾器模式對(duì)比
- C#裝飾器模式(Decorator Pattern)實(shí)例教程
- java設(shè)計(jì)模式之橋接模式(Bridge)
- java設(shè)計(jì)模式之組合模式(Composite)
- java設(shè)計(jì)模式之觀察者模式
- java設(shè)計(jì)模式之裝飾器模式(Decorator)