![Decorator](/images/patterns/cards/decorator-mini.png?id=d30458908e315af195cb183bc52dbef9)
Decorator em Ruby
O Decorator é um padrão estrutural que permite adicionar novos comportamentos aos objetos dinamicamente, colocando-os dentro de objetos wrapper especiais.
Usando decoradores, você pode agrupar objetos inúmeras vezes, pois os objetos de destino e os decoradores seguem a mesma interface. O objeto resultante terá um comportamento de empilhamento de todos os wrappers.
Complexidade:
Popularidade:
Exemplos de uso: O Decorator é bastante padrão no código Ruby, especialmente nos códigos relacionados a fluxos.
Identificação: O Decorator pode ser reconhecido por métodos de criação ou construtores que aceitam objetos da mesma classe ou interface que uma classe atual.
Exemplo conceitual
Este exemplo ilustra a estrutura do padrão de projeto Decorator. Ele se concentra em responder a estas perguntas:
- De quais classes ele consiste?
- Quais papéis essas classes desempenham?
- De que maneira os elementos do padrão estão relacionados?
main.rb: Exemplo conceitual
# The base Component interface defines operations that can be altered by
# decorators.
class Component
# @return [String]
def operation
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
end
end
# Concrete Components provide default implementations of the operations. There
# might be several variations of these classes.
class ConcreteComponent < Component
# @return [String]
def operation
'ConcreteComponent'
end
end
# The base Decorator class follows the same interface as the other components.
# The primary purpose of this class is to define the wrapping interface for all
# concrete decorators. The default implementation of the wrapping code might
# include a field for storing a wrapped component and the means to initialize
# it.
class Decorator < Component
attr_accessor :component
# @param [Component] component
def initialize(component)
@component = component
end
# The Decorator delegates all work to the wrapped component.
def operation
@component.operation
end
end
# Concrete Decorators call the wrapped object and alter its result in some way.
class ConcreteDecoratorA < Decorator
# Decorators may call parent implementation of the operation, instead of
# calling the wrapped object directly. This approach simplifies extension of
# decorator classes.
def operation
"ConcreteDecoratorA(#{@component.operation})"
end
end
# Decorators can execute their behavior either before or after the call to a
# wrapped object.
class ConcreteDecoratorB < Decorator
# @return [String]
def operation
"ConcreteDecoratorB(#{@component.operation})"
end
end
# The client code works with all objects using the Component interface. This way
# it can stay independent of the concrete classes of components it works with.
def client_code(component)
# ...
print "RESULT: #{component.operation}"
# ...
end
# This way the client code can support both simple components...
simple = ConcreteComponent.new
puts 'Client: I\'ve got a simple component:'
client_code(simple)
puts "\n\n"
# ...as well as decorated ones.
#
# Note how decorators can wrap not only simple components but the other
# decorators as well.
decorator1 = ConcreteDecoratorA.new(simple)
decorator2 = ConcreteDecoratorB.new(decorator1)
puts 'Client: Now I\'ve got a decorated component:'
client_code(decorator2)
output.txt: Resultados da execução
Client: I've got a simple component:
RESULT: ConcreteComponent
Client: Now I've got a decorated component:
RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))