Login Login
MORE

WIDGETS

Widgets

Wanted articles
Who is online?
Article tools

CSharp:Design Pattern Decorator

From Aino Wiki

Jump to: navigation, search

Introduzione

E' un pattern progettuale di tipo Strutturale, consente di aggiungere dinamicamente nuove funzionalità (responsabilità) ad oggetti già esistenti. Questo viene realizzato costruendo una nuova classe decoratore che "avvolge" l'oggetto originale. Al costruttore del decoratore si passa come parametro l'oggetto originale. È altresì possibile passarvi un differente decoratore. In questo modo, più decoratori possono essere concatenati l'uno all'altro, aggiungendo così in modo incrementale funzionalità alla classe concreta (che è rappresentata dall'ultimo anello della catena).

La concatenazione dei decoratori può avvenire secondo una composizione arbitraria: il numero di comportamenti possibili dell'oggetto composto varia dunque sensibilmente rispetto al numero dei decoratori disponibili.

Questo pattern è una valida alternativa all'uso dell'ereditarietà singola o multipla. Con l'ereditarietà, infatti, l'aggiunta di funzionalità avviene staticamente secondo i legami definiti nella gerarchia di classi e non è possibile ottenere al run-time una combinazione arbitraria delle funzionalità, né la loro aggiunta/rimozione.

Diagramma preso da Wikipedia:

Decorator UML class diagram.png

Esempio

Esempio frutto del corso su Lynda.com (di LinkedIn)
Supponiamo di implementare un configuratore di auto, il prodotto finale non è prevedibile inizialmente ma dipende dalle scelte dell'utente. Un approccio mediante ereditarietà (con classi derivate) sarebbe complicato ma per avere il risultato finale dinamicamente si potrà elegantemente ottenere usando il Decorator.
Decorator pattern 01.png

Diagramma della classi generico che seguirà l'esempio proposto:

Decorator pattern ClassDiagram 01.png

Codice

Seguendo il diagramma delle classi di prima, si son create delle cartelle ognuna relativa ad un rettangolo del diagramma. Segue La struttura della solution:

DesignPatterns Codice Solution.png

Component

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Decorator.Component
{
    // Component
    public abstract class Car
    {
        public string Description { get; set; }
        public abstract string GetDescription();
        public abstract double GetCarPrice();
    }
}

ConcreteComponent

CompactCar.cs

using Decorator.Component;
 
namespace Decorator.ConcreteComponent
{
    // ConcreteComponent
    public class CompactCar : Car
    {
        public CompactCar()
        {
            Description = "Compact Car";
        }
 
        public override string GetDescription() => Description;
        public override double GetCarPrice() => 10000.00;        
    }
}

FullSizeCar.cs

using Decorator.Component;
 
namespace Decorator.ConcreteComponent
{
    // ConcreteComponent
    public class FullSizeCar : Car
    {
        public FullSizeCar()
        {
            Description = "FullSize Car";
        }
 
        public override double GetCarPrice() => 30000.00;
        public override string GetDescription() => Description;
    }
}

Decorator

Questa classe verrà ereditata al fine di usarla per aggiungere caratteristiche alla classe base

using Decorator.Component;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Decorator.Decorator
{
    // Decorator
    public class CarDecorator : Car
    {
        protected Car _car;
        public CarDecorator(Car car)
        {
            _car = car;
        }
 
        public override double GetCarPrice() => _car.GetCarPrice();
 
        public override string GetDescription() => _car.GetDescription();
    }
}

ConcreteDecorator

Sostanzialmente la funzione che aggiunge caratteristiche a quelle già eseistenti nella classe passata nel costruttore, è la concatenazione di stringhe ottenuta mediante una specie di ricorsone che risale tutte "Descrition" delle classi derivare. LeatherSeats.cs

using Decorator.Component;
using Decorator.Decorator;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Decorator.ConcreteDecorator
{
    public class LeatherSeats : CarDecorator
    {
        public LeatherSeats(Car car) : base(car)
        {
            Description = "Leather Seats";
        }
 
        public override string GetDescription() => 
                               $"{_car.GetDescription()},  {Description}";
 
 
        public override double GetCarPrice() => _car.GetCarPrice() + 2500;
    }
}

Navigation.cs.cs

using Decorator.Component;
using Decorator.Decorator;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Decorator.ConcreteDecorator
{
    public class Navigation : CarDecorator
    {
        public Navigation(Car car)
            : base(car)
        {
            Description = "Navigation";
        }
 
        public override string GetDescription() =>
                               $"{_car.GetDescription()}, {Description}";
 
        public override double GetCarPrice() => _car.GetCarPrice() + 5000;
    }
}

Sunroof.cs

using Decorator.Component;
using Decorator.Decorator;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Decorator.ConcreteDecorator
{
    public class Sunroof : CarDecorator
    {
        public Sunroof(Car car) : base(car)
        {
            Description = "Sunroof";
        }
 
        public override string GetDescription() => $"{_car.GetDescription()}, {Description}";
 
        public override double GetCarPrice() => _car.GetCarPrice() + 2500;
    }
}

Program Main

using Decorator.Component;
using Decorator.ConcreteComponent;
using Decorator.ConcreteDecorator;
using System;
 
namespace Decorator
{
    class Program
    {
        static void Main(string[] args)
        {
            Car theCar = new CompactCar();
            theCar = new Navigation(theCar);
            theCar = new Sunroof(theCar);
            theCar = new LeatherSeats(theCar);
 
            Console.WriteLine(theCar.GetDescription());
            Console.WriteLine($"{theCar.GetCarPrice():C2}");
            Console.ReadKey();
        }
    }
}

Mappa e Link


C# | Design Pattern | Teoria


Visual Studio


Parole chiave:

Author Giuseppe AINO