Autumn SALE
Dekorator

Dekorator w języku Ruby

Dekorator to strukturalny wzorzec pozwalający na dodawanie obiektom nowych obowiązków w sposób dynamiczny — poprzez “opakowywanie” ich w specjalne obiekty posiadające potrzebną funkcjonalność.

Stosując dekoratory można opakowywać obiekty wielokrotnie, gdyż zarówno obiekt docelowy jak i dekoratory są zgodne pod względem interfejsu. Wynikowy obiekt będzie posiadał ułożoną w formie stosu połączoną funkcjonalność wszystkich “opakowań”.

Złożoność:

Popularność:

Przykłady użycia: Dekorator jest dość typowy w kodzie Ruby, szczególnie tym dotyczącym strumieni.

Identyfikacja: Dekorator można poznać po metodach kreacyjnych lub konstruktorach przyjmujących obiekty tej samej klasy lub interfejsu jako bieżącą klasę.

Przykład koncepcyjny

Poniższy przykład ilustruje strukturę wzorca Dekorator ze szczególnym naciskiem na następujące kwestie:

  • Z jakich składa się klas?
  • Jakie role pełnią te klasy?
  • W jaki sposób elementy wzorca są ze sobą powiązane?

main.rb: Przykład koncepcyjny

# 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: Wynik działania

Client: I've got a simple component:
RESULT: ConcreteComponent

Client: Now I've got a decorated component:
RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))

Dekorator w innych językach

Dekorator w języku C# Dekorator w języku C++ Dekorator w języku Go Dekorator w języku Java Dekorator w języku PHP Dekorator w języku Python Dekorator w języku Rust Dekorator w języku Swift Dekorator w języku TypeScript