Overview
If you are engaged in object-oriented development, the implementation of a class or object to increase behavior, the use of inheritance mechanism, this is a basic feature of all object-oriented languages. If a class that already exists lacks certain methods, or needs to add more functionality (glamour) to the method, you may simply inherit the class to produce a new class-which is built on extra code.
Inheriting an existing class makes it possible for subclasses to have methods of the parent class while owning their own methods. However, this method is static and the user cannot control the way and the time to increase the behavior. What do you do if you want to change the behavior of an already initialized object? Or, what do you want to do with the behavior of many classes? The previous one can only be done at run time, the latter is obviously possible, but may lead to a large number of different classes-terrible things.
problem
How do you organize your code so that it can easily add basic or some rarely used features, rather than writing directly without extra code inside your class?
Solution
- Dynamically add some additional responsibilities or behaviors to an object. Decorator mode is more flexible than generating subclasses in terms of adding functionality.
- Provides a flexible solution for changing subclasses. The adorner pattern expands the functionality of an object dynamically without having to change the original class file and using inheritance. It is by creating a wrapper object that is decorated to wrap the real object.
- Adorner mode is more useful when used with a set of subclasses. If you have a family of subclasses (derived from a parent class), you need to add additional features to separate use with subclasses, and you can use adorner patterns to avoid code duplication and increase in the number of specific subclasses.
Applicability
Use decorator mode in the following situations
- Add responsibilities to a single object in a dynamic, transparent manner without affecting other objects.
- Handle the duties that can be undone.
- When the method for generating subclasses cannot be extended. One scenario is that there may be a large number of independent extensions,
To support each combination will produce a large number of subclasses, resulting in an explosive increase in the number of subclasses.
Another scenario might be because the class definition is hidden, or the class definition cannot be used to generate subclasses.
instance
Class Simplewriter Def initialize (path) @file = File.Open (Path, "W") End def Write_line (line) @file. Print (l
INE) @file. Print ("\ n") End #字符数 def POS @file. Pos End #它将会将文件指针指向文件的开头 def Rewind @file. Rewind End def close @file. Colse End-SW = Simplewriter.new ("test.txt") sw.write_line ("Hello") puts Sw.pos PU TS Sw.rewind #基类 class Writerdecorator def initialize (real_writer) @real_writer = Real_writer End def WRI Te_line @real_writer. Write_line End def POS @real_writer. Pos End def Rewind @real_writer. Rewind E nd def close @real_writer. Close End Class Numberingwriter < Writerdecorator Attr:line_number de F Initialize (Real_writer) Super (real_writer) @line_number = 1 End #实际调用的是WriterDecorator的write_line方法, only in the written Pre-add number (decoration) #所以说NumberingWriter对WriterDecorator的接口wirte_line进行了装饰 # def write_line (line) @real_writer. Write_line ( "#{@line_number}:#{line}") @line_number + + 1 End sw = simplewriter.new (" numbering_write.txt ") NW = numberingwriter.new (SW) Nw.writ
E_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_lin E (line) line.each_byte{|byte| @check_num + + byte% 256} @real_writer. Write_line (line) End-SW = Simplewrit Er.new ("Check_num_writer.txt") CSW = checksummingwriter.new (sw) csw.write_line ("Hello,world") puts Csw.check_num cl Ass Timestampingwriter < Writerdecorator def initialize (real_writer) super (Real_writer) End Def Write_li NE (line) @real_writer. Write_line (' #{time.now}: #{line} ') End #倒着看 #5. The actual call is the Simplewriter Write_line method, which writes the contents to the file SW = simplewriter.new ("Mix.txt") #4. The actual call is the Numberingwriter Write_line method, the input of the data before the number # and then passed to @real_writer, at this time @real_witer for sw NW = NumberiNgwriter.new (SW) #3. The actual call is the Timestampingwriter Write_line method, the input of the data before the timestamp # then passed to @real_writer, at this time @real_witer for NW TSW = Timestampingwriter.new (NW) #2. The actual call is the Checksummingwriter Write_line method, the input data to the number of bytes of statistics # and then passed to @real_writer, at this time @real_witer for tsw CSW = Checksummingwriter.new (TSW) #1.
CSW calls Write_line csw.write_line ("Hello,world") puts Csw.check_num
Two ruby-style decorative pattern applications
(1) using extend to infiltrate the module
Class Simplewriter
def initialize (path)
@file = File.Open (Path, "w")
end
def write_line (line)
@ File.print (line)
@file. Print ("\ n") End
#字符数
def POS
@file. Pos End
# It will point the file pointer at the beginning of the file
def Rewind
@file. Rewind End
def close
@file. Colse
#使用extend方法动态的混入模块 to decorate the
module Timestampingwriter
def write_line (line)
super ("#{time.now}": #{line} ") 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
The last module that is joined is called first, and then the Write_line method of the parent class is called through Super.
In the example, precede the text with a timestamp, add the number, and then write the file
SW = simplewriter.new ("Out3.txt")
sw.extend (numberingwriter)
sw.extend (timestampingwriter)
Sw.write_ Line ("Hello,ruby")
(2) using the alias keyword
Class Simplewriter
def initialize (path)
@file = File.Open (Path, "w")
end
def write_line (line)
@file. Print (line)
@file. Print ("\ n") End
#字符数
def POS
@file. Pos End
# It will point the file pointer at the beginning of the file
def Rewind
@file. Rewind End
def close
@file. Colse
another dynamic way for Ruby to implement a decorative pattern is to
modify an instance method of an object, so the timestamp is added to the Out1.txt file without affecting the timestamp in the object sw2,out2.txt.
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")