Decorator (patrono de designo)

Le patrono Decorator responde al necessitate de appender dynamicamente le functionalitate a un objecto. Isto permitte evitar de crear classes successive qui heredita del prime e incorpora le nove functionalitate, sed, in vice, alteres qui implementa lo e se associa al prime.

Decorator
instantia de: Patrono de designo
subclasse de: structural pattern[*]


Commons: Decorator pattern

Motivation modificar

Un exemplo pro poter vider le applicabilitate del patrono decorator poterea esser le sequente:

  • On dispone de un utensile pro crear interfacies graphic, qui permitte de appender functionalitates como bordos o barras de displaciamento a un qualcunque componente del interfacie.
  • Un possibile solution esserea usar le hereditate pro extender le responsabilitates del classe. Si on selectiona iste solution, on facerea un designo inlexibile (static), durante que le cliente non pote controlar quando e como decorar le componente con aquelle proprietate.
  • Le solution es de encapsular dentro de altere objecto, nominate Decorator, le nove responsabilitates. Le decorator redirige le petitiones al componente e, de plus, pote realisar actiones additional ante e post le redirection. De iste maniera, on pote appender decoratores con qualitates appendite recursivemente.

 

  • In iste diagramma de classes, on pote vider que le interfacie decorator implementa le interfacie del componente, e redirige tote le methodos al componente visual le qual illo encapsula.
  • Le subclasses decorator raffina le methodos del componente, per adder responsabilitates.
  • Anque on pote vider que le cliente non necessita de facer un distinction inter le componentes visual decorate e le componentes sin decoration.

 

Applicabilitate modificar

  • Appender responsabilitates a objectos individual de forma dynamic e transparente
  • Responsabilitates de un objecto pote esser retirate
  • Quando le extension mediante le hereditate non es viabile.
  • Il ha un necessitate de extender le functionalitate de un classe, sed il non ha rationes pro extender lo a transverso del hereditate.
  • Il ha le necessitate de extender dynamicamente le functionalitate de un objecto e forsan quitar le functionalitate extendite.

Structura modificar

 

Participantes modificar

  • Componente

Defini le interfacie pro le objectos qui pote haber responsabilitates appendite.

  • Componente Concrete

Defini un objecto al qual on pote aggregar responsabilitates additional.

  • Decorator

Mantene un referentia al componente associate. Implementa le interfacie del superclasse Componente per delegar in le componente associate.

  • Decorator Concrete

Appende responsabilitates al componente.

Collaborationes modificar

  • Le decorator redirige le petitiones al componente associate.
  • Optionalmente illo pote realisar cargas additional ante e post rediriger le petition.

Consequentias modificar

  • Plus flexibile que le hereditate. Al utilisar iste patrono, on pote appender e eliminar responsabilitates in tempore de execution. De plus, illo evita le uso del hereditate con multe classes e anque, in alcun casos, le hereditate multiple.
  • Illo evita le apparition de classes con multe responsabilitates in le classes superior del hierarchia. Iste patrono permitte al programmator de incorporar responsabilitates de modo incremental.
  • Illo genera grande quantitate de objectos parve. Le uso de decoratores da como resultato systemas formate per multe objectos parve e simile.
  • Il pote haber problemas con le identitate del objectos. Un decorator se comporta como un copertura transparente, sed ab le puncto de vista del identitate de objectos, istos non es identic, dunque on deberea evitar appoiar se in le identitate quando on usa decoratores.

Implementation modificar

Le patrono Decorator solutiona iste problema de un maniera multo plus simple e extensibile.

On crea a partir de Fenestra le subclasse abstracte FenestraDecorator e, per hereditar de illo, BordoDecorator e ButtonDeAdjutaDecorator. FenestraDecorator encapsula le comportamento de Fenestra e usa un composition recursive pro que sia possibile appender tante "revestimentos" de Decoratores quante on desira.

On pote crear tante Decorators como on vole per hereditar de FenestraDecorator.

Exemplo C++ modificar

#include <iostream>

//[Classe Component] vider diagramma de classes
class IFenestraAbstracte
{
public:
       
	virtual void Delinear() = 0;
};

//[Classe ConcreteComponent] vider diagramma de classes, Classe que on desira decorar
class Fenestra : public IFenestraAbstracte
{
public:
   
	void Delinear()
	{
		std::cout << " Fenestra ";
	}
};

//[Classe Decorator] vider diagramma de classes
class FenestraDecorator : public IFenestraAbstracte
{
public:
	FenestraDecorator(IFenestraAbstracte* fenestraAbstracte)
	{
		_FenestraAbstracte = fenestraAbstracte;
	}
        
	virtual void Delinear() = 0;
        
protected:
	IFenestraAbstracte* _FenestraAbstracte;
};

//[Classe ConcreteDecorator] vider diagramma de classes
class BordoDecorator : public FenestraDecorator
{
public:
	BordoDecorator(IFenestraAbstracte* fenestraAbstracte) : FenestraDecorator(fenestraAbstracte)
	{
	}
        
	virtual void Delinear()
	{
		std::cout << "|";
		_FenestraAbstracte->Delinear();
		std::cout << "|";
	}
};

//[Classe ConcreteDecorator] vider diagramma de classes
class ButtonDeAdjutaDecorator : public FenestraDecorator
{
public:
	ButtonDeAdjutaDecorator(IFenestraAbstracte* fenestraAbstracte) : FenestraDecorator(fenestraAbstracte)
	{
	}
        
	virtual void Delinear()
	{
		_FenestraAbstracte->Delinear();
		std::cout << "[Button de Adjuta]";
	}
};

int main()
{
	ButtonDeAdjutaDecorator* fenestraConButtonDeAdjuta = new ButtonDeAdjutaDecorator(new Fenestra());
	fenestraConButtonDeAdjuta->Delinear();
	std::cout << std::endl;

	BordoDecorator* fenestraConButtonDeAdjutaEBordo = new BordoDecorator(fenestraConButtonDeAdjuta);
	fenestraConButtonDeAdjutaEBordo->Delinear();
	std::cout << std::endl;

	BordoDecorator* fenestraConBordo = new BordoDecorator(new Fenestra());
	fenestraConBordo->Delinear();
	std::cout << std::endl;

	BordoDecorator* fenestraConDupleBordo = new BordoDecorator(fenestraConBordo);
	fenestraConDupleBordo->Delinear();
	std::cout << std::endl;
    
	delete fenestraConButtonDeAdjuta;
	delete fenestraConButtonDeAdjutaEBordo;
	delete fenestraConBordo;
	delete fenestraConDupleBordo;
        
	return 0;
}

Exemplo C# modificar

using System;
using System.Collections.Generic;
using System.Text;

namespace Decorator
{
	class Program
	{
		static void Main(string[] args)
		{
			BordoDecorator fenestraConButtonDeAdjutaEBordo = new BordoDecorator(fenestraConButtonDeAdjuta);
			fenestraConButtonDeAdjutaEBordo.Delinear();
			Console.WriteLine();

			BordoDecorator fenestraConBordo = new BordoDecorator(new Fenestra());
			fenestraConBordo.Delinear();
			Console.WriteLine();

			BordoDecorator fenestraConDupleBordo = new BordoDecorator(fenestraConBordo);
			fenestraConDupleBordo.Delinear();
			Console.WriteLine();
                       
			Console.Read();
		}
        
		//[Classe Component] vider diagramma de classes
		public interface IFenestraAbstracte
		{
			void Delinear();
		}

		//[Classe ConcreteComponent] vider diagramma de classes, Classe que on desira decorar
		public class Fenestra : IFenestraAbstracte
		{
			public void Delinear() 
			{
				Console.Write(" Fenestra ");
			}
		}

		//[Classe Decorator] vider diagramma de classes
		public abstract class FenestraDecorator : IFenestraAbstracte
		{
			public FenestraDecorator(IFenestraAbstracte fenestraAbstracte) 
			{ 
				_FenestraAbstracte = fenestraAbstracte;
			}
			
			protected IFenestraAbstracte _FenestraAbstracte;
			
			public abstract void Delinear();
		}

		//[Classe ConcreteDecorator] vider diagramma de classes
		public class BordoDecorator : FenestraDecorator
		{
			public BordoDecorator(IFenestraAbstracte fenestraAbstracte) : base(fenestraAbstracte) 
			{
			}

			public override void Delinear() 
			{
				Console.Write("|");
				_FenestraAbstracte.Delinear();
				Console.Write("|");
			}            
		}

		//[Classe ConcreteDecorator] vider diagramma de classes
		public class ButtonDeAdjutaDecorator : FenestraDecorator
		{
			public ButtonDeAdjutaDecorator(IFenestraAbstracte fenestraAbstracte) : base(fenestraAbstracte) 
			{
			}

			public override void Delinear() 
			{
				_FenestraAbstracte.Delinear();
				Console.Write("[Button de Adjuta]");
			}            
		}
	}
}

Exemplo Java modificar

 
public abstract class Componente
{
	abstract public void operation();
}
 
public class ComponenteConcrete extends Componente
{
	public void operation()
	{
		System.out.println("ComponenteConcrete.operation()");
	}
}
 
public abstract class Decorator extends Componente
{
	private Componente _componente;
 
	public Decorator(Componente componente)
	{
		_componente = componente;
	}
 
	public void operation()
	{
		_componente.operation();
	}
}
 
public class DecoratorConcreteA extends Decorator
{
	private String _proprietateAppendite;
 
	public DecoratorConcreteA(Componente componente)
	{
		super(componente);
	}
 
	public void operation()
	{
		super.operation();
		_proprietateAppendite = "Nove proprietate";
		System.out.println("DecoratorConcreteA.operation()");
	}
}
 
public class DecoratorConcreteB extends Decorator
{
	public DecoratorConcreteB(Componente componente)
	{
		super(componente);
	}
 
	public void operation()
	{
		super.operation();
		comportamentoAppendite();
		System.out.println("DecoratorConcreteB.operation()");
	}
 
	public void comportamentoAppendite()
	{
		System.out.println("Comportamento B appendite");
	}
}
 
public class Cliente
{
	public static void main(String[] args)
	{
		ComponenteConcrete c = new ComponenteConcrete();
		DecoratorConcreteA d1 = new DecoratorConcreteA(c);
		DecoratorConcreteB d2 = new DecoratorConcreteB(d1);
		d2.operation();
	}
}

Exemplo Python modificar

def establir_costo_decorator(function):
	def copertura1(instantia, costo):
		function(instantia, costo)
	return copertura1
 
def obtener_costo_decorator(costo_additional):
	def copertura1(function):
		def copertura2(instantia):
			return function(instantia) + costo_additional
		return copertura2
	return copertura1
 
class Caffe(object):
	@establir_costo_decorator
	def establir_costo(self, costo):
		self.costo = costo
 
	@obtener_costo_decorator(0.5)
	@obtener_costo_decorator(0.7)
	@obtener_costo_decorator(0.2)
	def obtener_costo(self):
		return self.costo
 
caffe = Caffe()
caffe.establir_costo(1.0)
print caffe.obtener_costo() # 2.4

Exemplo de PHP modificar

<?php
interface iCoffee
{
	public function getBaseCost();
}

class Coffee implements iCoffee
{
	protected $_baseCost = 0;
	
	public function getBaseCost()
	{
		return $this->_baseCost;
	}
}

class BlackCoffee extends Coffee
{
	public function __construct()
	{
		$this->_baseCost = 5;
	}
}

abstract class CoffeeDecorator implements iCoffee
{
	protected $_coffee;
	
	public function __construct(iCoffee $Coffee)
	{
		$this->_coffee = $Coffee;
	}
}

class WithCream extends CoffeeDecorator
{
	public function getBaseCost()
	{
		return $this->_coffee->getBaseCost() + 1.5;
	}
}

class WithMilk extends CoffeeDecorator
{
	public function getBaseCost()
	{
		return $this->_coffee->getBaseCost() + 4;
	}
}

class WithChocolate extends CoffeeDecorator
{
	public function getBaseCost()
	{
		return $this->_coffee->getBaseCost() + 5;
	}
}

$coffee = new WithChocolate(new WithMilk(new WithCream(new BlackCoffee())));
echo 'Le precio del caffe es: $' . $coffee->getBaseCost();

Ligamines externe modificar

 
Nota