czwartek, 5 lipca 2012

[Wzorce projektowe] Bridge

Analogia z życia:

Niektóre restauracje oferują jedynie zestawy obiadowe. Zestaw obiadowy zawsze musi się składać z zupy i drugiego dania. Każdego dnia mamy do dyspozycji inne zupy i inne drugie dania, gdzie zupa i drugie danie to pojęcia abstrakcyjne. Zestaw obiadowy jako całość zawsze tworzą konkretna zupa i konkretne drugie danie. Jeśli chcemy rozbudować taki zestaw o sałatkę, wystarczy powiedzieć, że zestaw obiadowy składa się z zupy, drugiego dania i sałatki.


Zastosowanie:

Definicja mówi, że mostu należy używać wszędzie tam, gdzie chcemy oddzielić abstrakcję od implementacji tak, aby istniały niezależnie. Przykładem mogą być interfejsy użytkownika.Chcemy na przykład rysować na ekranie różne figury różnymi kolorami. Pojęciem abstrakcyjnym jest kolorowa figura, przykładem konkretnej implementacji czerwony trapez.

Zasada działania:

Często spotykanym sposobem implementacji jest klasa abstrakcyjna reprezentująca abstrakcyjne pojęcie. Z klasy tej dziedziczą konkretne implementacje. Klasa abstrakcyjna zawiera pole lub propercję typu pewnego interfejsu który reprezentuje kolejną abstrakcję. Jedyny konstruktor dla klas implementujących bazową klasę abstrakcyjną to taki, w którym jednym z argumentów jest obiekt implementujący potrzebny interfejs.


Przykład implementacyjny:


 public abstract class Vector
    {
        protected Norm Norm { get; set; }
        protected float[] Coefficients { get; set; }

        protected Vector(Norm n)
        {
            this.Norm = n;
        }

        public void NormName()
        {
            Norm.PrintName();
        }

        public double Calculate()
        {
            return Norm.Calculate(Coefficients);
        }

    }

    public class Vector3D : Vector
    {
        public Vector3D(Norm norm, float x, float y, float z) : base(norm)
        {
            Coefficients = new float[] { x, y, z};
        }
    }

    public class Vector2D : Vector
    {
        public Vector2D(Norm norm, float x, float y) : base(norm)
        {
            Coefficients = new float[] { x, y};
        }
    }

 public abstract class Norm
    {
        public abstract void PrintName();
        public abstract double Calculate(float[] coeffs);
    }

    public class EuclideanNorm : Norm
    {

        public override void PrintName()
        {
            Console.WriteLine("Calculating Euclidean Norm");
        }

        public override double Calculate(float[] coeffs)
        {
            float norm = 0.0f;
            foreach (var coeff in coeffs)
            {
                norm += coeff*coeff;
            }
            return Math.Sqrt((double) norm);
        }
    }

    public class ManhattanNorm : Norm
    {

        public override void PrintName()
        {
            Console.WriteLine("Calculating Manhattan Norm");
        }

        public override double Calculate(float[] coeffs)
        {
            return coeffs.Sum(s => Math.Abs(s));
        }
    }
 class Program
    {
        static void Main(string[] args)
        {
            Vector v1 = new Vector2D(new ManhattanNorm(), 2.0f, 3.5f);
            Vector v2 = new Vector3D(new EuclideanNorm(), 4.0f, 4.6f, 3.4f);

            v1.NormName();
            Console.WriteLine(v1.Calculate().ToString());

            v2.NormName();
            Console.WriteLine(v2.Calculate().ToString());

            Console.Read();
        }
    }

Korzystając z pewnego schematu dla wzorca mostu można opisać powyższy przykład


Abstrakcję reprezentuje klasa Vector, która zawiera realizatora w postaci normy. Konkretni realizatorzy to dwie konkretne normy natomiast konkretne abstrakcje to wektory 2D i 3D

1 komentarz: