範文齋

位置:首頁 > 行業範文 > 設計

實例講解Ruby使用設計模式中的裝飾器模式的方法參考

設計5.16K

概述

實例講解Ruby使用設計模式中的裝飾器模式的方法參考

若你從事過面向對象開發,實現給一個類或對象增加行爲,使用繼承機制,這是所有面向對象語言的一 個基本特性。如果已經存在的一個類缺少某些方法,或者須要給方法添加更多的功能(魅力),你也許會僅僅繼承這個類來產生一個新類—這建立在額外的代碼上。

通過繼承一個現有類可以使得子類在擁有自身方法的同時還擁有父類的方法。但是這種方法是靜態的,用戶不能控制增加行爲的方式和時機。如果 你希望改變一個已經初始化的對象的行爲,你怎麼辦?或者,你希望繼承許多類的行爲,改怎麼辦?前一個,只能在於運行時完成,後者顯然時可能的,但是可能會導致產生大量的不同的類—可怕的事情。

問題

你如何組織你的代碼使其可以容易的添加基本的或者一些很少用到的 特性,而不是直接不額外的代碼寫在你的類的內部?

解決方案

動態地給一個對象添加一些額外的職責或者行爲。就增加功能來說, Decorator模式相比生成子類更爲靈活。 提供了改變子類的靈活方案。裝飾器模式在不必改變原類文件和使用繼承的情況下,動態的`擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。 當用於一組子類時,裝飾器模式更加有用。如果你擁有一族子類(從一個父類派生而來),你需要在與子類獨立使用情況下添加額外的特性,你可以使用裝飾器模式,以避免代碼重複和具體子類數量的增加。

適用性

以下情況使用Decorator模式

在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責。 處理那些可以撤消的職責。 當不能採用生成子類的方法進行擴充時。一種情況是,可能有大量獨立的擴展,

爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增長。

另一種情況可能是因爲類定義被隱藏,或類定義不能用於生成子類。

實例

class SimpleWriter def initialize(path) @file = (path,"w") end def write_line(line) @t(line) @t("n") end #字符數 def pos @ end #它將會將文件指針指向文件的開頭 def rewind @nd end def close @e end end sw = ("") e_line("你好") puts puts nd #基類 class WriterDecorator def initialize(real_writer) @real_writer = real_writer end def write_line @real_e_line end def pos @real_ end def rewind @real_nd end def close @real_e end end class NumberingWriter < WriterDecorator attr :line_number def initialize(real_writer) super(real_writer) @line_number = 1 end #實際調用的是WriterDecorator的write_line方法,只是在寫入的內容前加上了編號(裝飾) #所以說NumberingWriter對WriterDecorator的接口wirte_line進行了裝飾 # def write_line(line) @real_e_line("#{@line_number}:#{line}") @line_number += 1 end end sw = ("numbering_") nw = (sw) e_line("hello,world") e_line("hello,ruby") puts _number class CheckSummingWriter < WriterDecorator attr_reader :check_num def initialize(real_writer) super(real_writer) @check_num = 0 end def write_line(line) _byte{|byte| @check_num += byte % 256} @real_e_line(line) end end sw = ("check_num_") csw = (sw) e_line("hello,world") puts k_num class TimeStampingWriter < WriterDecorator def initialize(real_writer) super(real_writer) end def write_line(line) @real_e_line("#{}: #{line}") end end #倒着看 #5. 實際調用的是SimpleWriter得write_line方法,將內容寫入文件 sw = ("") #4. 實際調用的是NumberingWriter得write_line方法,對在輸入的數據前加上了編號 # 然後傳給@real_writer,此時的@real_witer爲sw nw = (sw) #3. 實際調用的是TimeStampingWriter得write_line方法,對在輸入的數據前加上了時間戳 # 然後傳給@real_writer,此時的@real_witer爲nw tsw = (nw) #2. 實際調用的是CheckSummingWriter得write_line方法,對輸入的數據進行了字節數的統計 # 然後傳給@real_writer,此時的@real_witer爲tsw csw = (tsw) #1. csw調用write_line e_line("hello,world") puts k_num

兩種ruby風格的裝飾模式應用

(1)使用extend混入模塊

class SimpleWriter def initialize(path) @file = (path,"w") end def write_line(line) @t(line) @t("n") end #字符數 def pos @ end #它將會將文件指針指向文件的開頭 def rewind @nd end def close @e end end #使用extend方法動態的混入模塊,來進行裝飾 module TimeStampingWriter def write_line(line) super("#{}:#{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

最後被加入的模塊,先被調用,然後通過super來調用父類的write_line方法。

例子中先在文本的前面加上時間戳,在加入編號,最後寫入文件

sw = ("") nd(NumberingWriter) nd(TimeStampingWriter) e_line("hello,ruby")

(2)使用alias關鍵字

class SimpleWriter def initialize(path) @file = (path,"w") end def write_line(line) @t(line) @t("n") end #字符數 def pos @ end #它將會將文件指針指向文件的開頭 def rewind @nd end def close @e end end ruby實現裝飾模式的另一種動態方法 : 修改對象的實例方法, 所以在文件中會加入時間戳,而不影響對象sw2,中不會加入時間戳 。 sw1 = ("") class << sw1 alias old_write_line write_line def write_line(line) old_write_line("#{}:#{line}") end end e_line("hello,world") sw2 = ("") e_line("hello,world")