The Decorator pattern is used when you need to add some feature to a class with wrapper rather than write a new method.
Think about the writer support chechsum write, line number write:
class EnhancedWriter
attr_reader :check_sum
def initialize(path)
@file = File.open(path, "w")
@check_sum = 0
@line_number = 1
end
def write_line(line)
@file.print(line)
@file.print("\n")
end
def checksumming_write_line(data)
data.each_byte {|byte| @check_sum = (@check_sum + byte) % 256 }
@check_sum += "\n"[0] % 256
write_line(data)
end
def timestamping_write_line(data)
write_line("#{Time.new}: #{data}")
end
def numbering_write_line(data)
write_line("%{@line_number}: #{data}")
@line_number += 1
end
def close
@file.close
end
end
then when we write the plain text:
writer = EnhancedWriter.new('out.txt')
writer.write_line("A plain line")
when we write the checksum text:
writer.checksumming_write_line('A line with checksum')
puts("Checksum is #{writer.check_sum}")
when we write a time-stamped line or a numbered one:
writer.timestamping_write_line('with time stamp')
writer.numbering_write_line('with line number')
There is only one thing wrong with this approach: everything. First, every client that uses EnhancedWriter will need to know whether it is writing out numbered, checksummed, or time-stamped text.
So we can use inheritant way to solve the problem:
class EnhancedWriter
class NumberingWriter < EnhancedWriter
class TimestampedWriter < EnhancedWriter
class CheckSummedWriter < EnhancedWriter
class NumberingCheckSummedWriter < NumberingWriter
class TimestampedNumberingWriter < TimestampedWriter
class CheckSummedWriterLineNumberingWriter < CheckSummedWriter
If you need a more complex writer with three feature, then it will be a mess.
A better solution would allow you to assemble the combination of features that you
really need:
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
def rewind
@file.rewind
end
def close
@file.close
end
end
Then decorator will be:
class WriterDecorator
def initialize(real_writer)
@real_writer = real_writer
end
def write_line(line)
@real_writer.write_line(line)
end
def pos
@real_writer.pos
end
def rewind
@real_writer.rewind
end
def close
@real_writer.close
end
end
class NumberingWriter < WriterDecorator
def initialize(real_writer)
super(real_writer)
@line_number = 1
end
def write_line(line)
@real_writer.write_line("#{@line_number}: #{line}")
@line_number += 1
end
end
The client need not to worry about it is SimpleWriter or NumberingWriter instance:
writer = NumberingWriter.new(SimpleWriter.new('final.txt'))
writer.write_line('Hello out there')
class CheckSummingWriter < WriterDecorator
attr_reader :check_sum
def initialize(real_writer)
@real_writer = real_writer
@check_sum = 0
end
def write_line(line)
line.each_byte {|byte| @check_sum = (@check_sum + byte) % 256 }
@check_sum += "\n"[0] % 256
@real_writer.write_line(line)
end
end
class TimeStampingWriter < WriterDecorator
def write_line(line)
@real_writer.write_line("#{Time.new}: #{line}")
end
end
The featured object we need can composed by:
writer = CheckSummingWriter.new(TimeStampingWriter.new(
NumberingWriter.new(SimpleWriter.new('final.txt'))))
writer.write_line('Hello out there')
The WriterDecorator is just a delegator class, we can use forwardable module
require 'forwardable'
class WriterDecorator
extend Forwardable
def_delegators :@real_writer, :write_line, :rewind, :pos, :close
def initialize(real_writer)
@real_writer = real_writer
end
end
A Ruby dynamic solution of decorator problem is alias method:
w = SimpleWriter.new('out')
class << w
alias old_write_line write_line
def write_line(line)
old_write_line("#{Time.new}: #{line}")
end
end
This kind of method is common in Rails source code.
And the Ruby mix-in technique and dynamic extend method can also solve the problem:
module TimeStampingWriter
def write_line(line)
super("#{Time.new}: #{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
class Writer
define write(line)
@f.write(line)
end
end
w = SimpleWriter.new('out')
w.extend(NumberingWriter)
w.extend(TimeStampingWriter)
w.write_line('hello')
The calling sequence will be TimeStampingWriter => NumberingWriter => SimpleWriter
The good example of method alias decorator is alias_method_chain
分享到:
相关推荐
Design Patterns in Ruby, Addison-wesley (2008). The Addison-Wesley Professional Ruby Series provides readers with practical, people-oriented, and in-depth information about applying the Ruby platform ...
Addison.Wesley.Design.Patterns.in.Ruby.Dec.2007 高清PDF英文版
Design Patterns in Ruby Dec 2007.rar
Design Patterns in Modern C++.pdf
design pattern in C# language
Introduction to Design Patterns in C With Qt4 Alan Ezust
Design Patterns in Modern C++: Reusable Approaches for Object-Oriented Software Design English | PDF| 2018 | 312 Pages | ISBN : 1484236025Design Patterns in Modern C++: Reusable Approaches for Object...
Too often design patterns are explained using tricky concepts, when in fact they are easy to use and can enrich your everyday development. Design Patterns in ...
Learn how to implement design patterns in Java: each pattern in Java Design Patterns is a complete implementation and the output is generated using Eclipse, making the code accessible to all....
Pro Design Patterns in Swift shows you how to harness the power and flexibility of Swift to apply the most important and enduring design patterns to your applications, taking your development ...
An introduction to Design Patterns in C++ with Qt 2nd Edition 中文版 C++ qt 设计模式 第二版, 中英文版 合集 Master C++ “The Qt Way” with Modern Design Patterns and Efficient Reuse This fully ...
Implement design patterns in .NET using the latest versions of the C# and F# languages. This book provides a comprehensive overview of the field of design patterns as they are used in today’s ...
App Architecture: iOS Application Design Patterns in Swift 包含Source code 有钱请支持正版 没钱请默默学习 原书地址: https://www.objc.io/books/app-architecture 中文原书地址: ...
Design Patterns by Tutorials Learning design patterns in Swift 4.2, 2nd Edition.pdf
Data Structures And Algorithms With Object-oriented Design Patterns In Java.chm
Implement structural patterns such as adapter, bridge, decorator, facade and more Work with the behavioral patterns such as chain of responsibility, command, iterator, mediator and more Apply ...
Design Patterns in Java(2nd) 英文epub 第2版 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除
and applications that run on various software and hardware platforms with little or no change in the underlying codebase, while still being a native application with native capabilities and speed....