piątek, 6 lipca 2012

[Wzorce projektowe] Observer

Analogia z życia:

Grupy google umożliwiają prowadzenie rozległych dyskusji na konkretne tematy. Zakładając grupę dyskusyjną mamy możliwość wysyłania do niej wiadomości. Każdy zainteresowany tematem może sobie zasubskrybować grupę i otrzymywać wszystkie wysyłane na nią wiadomości. Jeśli temat przestanie go interesować, może anulować subskrypcję. Osoba wysyłająca wiadomości nie musi przejmować się tym, kto obecnie subskrybuje jej wiadomości - są one wysyłane na adres grupy.





Zastosowanie:

Wzorzec obserwatora stosujemy, gdy jeden obiekt zależny jest od innego i zmiana stanu jednego obiektu powinna powodować zmianę innych obiektów. Często używając wzorca obserwatora nie mamy wiedzy na temat tego, jakie obiekty powiadamiamy.

Zasada działania:

Tradycyjne podejście do wzorca obserwatora zakłada stworzenie dwóch klas abstrakcyjnych : podmiotu i obserwatora. Obserwator zawiera referencję do podmiotu i może go aktualizować. Podmiot może rejestrować nowych obserwatorów (zawiera kolekcję obserwatorów), a także usuwać już zarejestrowanych. Może także notyfikować wszystkich o zmianie stanu. Ponadto może się też zdarzyć, że obserwatorzy będą chcieli modyfikować źródło notyfikacji, co należy odpowiednio zaimplementować.

Przykład implementacyjny:


public interface IAbstractObserver
    {
        void Update(int number);
    }

    public class Counter : IAbstractObserver
    {
        public Counter(IAbstractSubject sub)
        {
            sub.Subscribe(this);
        }

        public static int Count { get; set; }

        public void Update(int n)
        {
            Count++;
        }
    }

    public class Printer : IAbstractObserver
    {
        public Printer(IAbstractSubject sub)
        {
            sub.Subscribe(this);
        }

        public void Update(int n)
        {
            Console.WriteLine(n);
        }
    }
public interface IAbstractSubject
    {
        void Subscribe(IAbstractObserver observer);
        void Unsubscribe(IAbstractObserver observer);
        void Notify();
    }

    public class RandomNumbers : IAbstractSubject
    {
        private List<IAbstractObserver> _observers = new List<IAbstractObserver>();


        private int _randomNumber;
        public int RandomNumber
        {
            get { return _randomNumber; }
            set
            {
                _randomNumber = value;
                Notify();
            }
        }

        public void Subscribe(IAbstractObserver observer)
        {
            _observers.Add(observer);
        }

        public void Unsubscribe(IAbstractObserver observer)
        {
            _observers.Remove(observer);
        }

        public void Notify()
        {
            foreach (IAbstractObserver abstractObserver in _observers)
            {
                abstractObserver.Update(_randomNumber);
            }
        }
    }
 class Program
    {
        static void Main(string[] args)
        {
            RandomNumbers rn = new RandomNumbers();
            Printer printer = new Printer(rn);
            Counter counter = new Counter(rn);

            Random r = new Random();

            for (int i = 0; i < 10; i++)
            {
                int number = r.Next(0, 10);
                rn.RandomNumber = number;
                Thread.Sleep(number*100);
            }

            Console.WriteLine(Counter.Count);
            Console.Read();
        }
    }

Powyższa implementacja jest podejściem klasycznym. Platforma .NET Framework udostępnia zdarzenia i delegatów, za pomocą których można uzyskać podobny efekt.

[Wzorce projektowe] Simple Factory, Abstract Factory

Analogia z życia:

Automat do napojów wyrzuca puszki takich samych rozmiarów z napojami różnych producentów. Decyzja o tym, którą puszkę zwrócić podejmowana jest w momencie, gdy użytkownik naciśnie odpowiednie przyciski i wrzuci odpowiednie monety. Całym procesem przeliczania oraz wybrania żądanego napoju zajmuje się automat.




Zastosowanie:

Fabryk używamy, kiedy chcemy oddzielić proces tworzenia obiektu od podejmowania decyzji o tym, który obiekt chcemy utworzyć. Znacznie ułatwia to rozszerzanie możliwości podczas dalszego rozwoju oprogramowania. Fabryki bywają także użyteczne, gdy informacje o tym, który obiekt mamy utworzyć przechowywane są poza programem, na przykład w bazie danych, pliku .xml etc. Zatem warto stosować fabryki, gdy nie jesteśmy pewni, której konkretnej implementacji danego interfejsu będziemy w danym miejscu potrzebowali. Często w kodzie może się pojawić sporo wyrażeń typu if-else lub switch podczas tworzenia obiektów. Można je również zastąpić fabryką.

Simple Factory:

Pierwsza wersja fabryki ma za zadanie enkapsulację tworzenia obiektów. Decyzja o tym, który obiekt ma zostać zbudowany może zostać podjęta w czasie trwania programu np. na podstawie pliku konfiguracyjnego. Pobranie obiektu odbywa się za pomocą metody GetInstance z parametrem typu string, skojarzonym z typem przez dot Netowe Reflection.


public interface IDrink
    {
        string GetName();
    }

    public class CocaCola : IDrink
    {
        public string GetName()
        {
            return "Coca - Cola";
        }
    }

    public class Pepsi : IDrink
    {
        public string GetName()
        {
            return "Pepsi";
        }
    }

    public class Sprite : IDrink
    {
        public string GetName()
        {
            return "Sprite";
        }
    }
public class DrinkFactory
    {
        private Dictionary<string, Type> _drinks;

        public DrinkFactory()
        {
            LoadDrinks();
        }

        public void LoadDrinks()
        {
            _drinks = new Dictionary<string, Type>();
            var types = Assembly.GetExecutingAssembly().GetTypes();
            foreach (var type in types)
            {
                if(type.GetInterface(typeof(IDrink).ToString())!= null)
                {
                    _drinks.Add(type.Name,type);
                }
            }
        }

        public IDrink GetInstance(string typeName)
        {
            foreach (KeyValuePair<string, Type> pair in _drinks)
            {
                if (pair.Key.ToLower().Contains(typeName.ToLower()))
                    return Activator.CreateInstance(pair.Value) as IDrink;
            }
            throw new NotImplementedException();
        }
    }
 class Program
    {
        static void Main(string[] args)
        {
            var factory = new DrinkFactory();

            IDrink drink = factory.GetInstance("Cola");
            Console.WriteLine(drink.GetName());
            drink = factory.GetInstance("pepsi");
            Console.WriteLine(drink.GetName());
        }
    }

Abstract Factory :

Fabryka abstrakcyjna zapewnia jedynie interfejs do tworzenia rodzin powiązanych ze sobą pewien sposób obiektów. Konkretne fabryki, będące implementacjami fabryki abstrakcyjnej umożliwiają tworzenie całych rodzin obiektów w zależności od parametru. Jedna fabryka może tym razem tworzyć wiele obiektów za pomocą różnych metod. Sposób tworzenia obiektów wewnątrz konkretnej fabryki może być całkowicie dowolny.




    public interface ICar
    {
        Engine Engine { get; set; }
        string Name { get; set; }
    }

    public class VWGolf : ICar
    {
        public Engine Engine { get; set; }

        public string Name
        {
            get { return "Volkswagen Golf"; }
            set { throw new NotImplementedException(); }
        }
    }

    public class FordFocus : ICar
    {
        public Engine Engine { get; set; }

        public string Name
        {
            get { return "Ford Focus"; }
            set { throw new NotImplementedException(); }
        }
    }
 abstract public class Engine
    {
        public int Capacity { get; set; }
    }

    public class GasEngine : Engine
    {
        public GasEngine()
        {
            Capacity = 30;
        }
    }

    public class PetrolEngine : Engine
    {
        public PetrolEngine()
        {
            Capacity = 50;
        }

    }
    public abstract class CarAbstractFactory
    {
        public abstract ICar CreateAutoWithPetrolEngine();
        public abstract ICar CreateAutoWithGasEngine();
    }

    public class VWGolfFactory : CarAbstractFactory
    {
        private ICar BaseCreate()
        {
            return new VWGolf();
        }

        public override ICar CreateAutoWithPetrolEngine()
        {
            var car = BaseCreate();
            car.Engine = new PetrolEngine();
            return car;
        }

        public override ICar CreateAutoWithGasEngine()
        {
            var car = BaseCreate();
            car.Engine = new GasEngine();
            return car;
        }
    }

    public class FordFocusFactory : CarAbstractFactory
    {

        public override ICar CreateAutoWithPetrolEngine()
        {
            var car = new FordFocus();
            car.Engine = new PetrolEngine();
            return car;
        }

        public override ICar CreateAutoWithGasEngine()
        {
            var car = new FordFocus();
            car.Engine = new GasEngine();
            return car;
        }
    }
static void Main(string[] args)
        {
            CarAbstractFactory factory = LoadFactory();
            var car = factory.CreateAutoWithGasEngine();
            Console.WriteLine(car.Name);
            Console.WriteLine(car.Engine.Capacity);
        }

        public static CarAbstractFactory LoadFactory()
        {
            Random rnd = new Random();
            if (rnd.Next() % 2 == 0)
                return new VWGolfFactory();
            return new FordFocusFactory();
        }

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

[Wzorce projektowe] Singleton

Analogia z życia:

Każde dziecko wie, że nieodłączną częścią każdego samochodu jest kierownica. Samochód zawiera dokładnie jedną kierownicę. Kierownica może być używana tylko przez jedną osobę, lub w ogóle nie używana. Gdyby kilka osób zaczęło kręcić kierownicą podczas jazdy to nietrudno sobie wyobrazić do czego by to doprowadziło. Gdyby samochód miał więcej kierownic. W najlepszym wypadku doszło by do czegoś takiego :-):



Zastosowanie:

Singletony tworzy się, gdy zachodzi potrzeba stworzenia dokładnie jednej instancji danej klasy. Dodatkowo wprowadza się blokowanie dwufazowe - zabezpieczenie instancji przed dostępem z wielu wątków. Obiekty - singletony podczas tworzenia nie potrzebują by przekazywać parametry za pomocą konstruktora. Czasami warto także zastanowić się nad stworzeniem singletonu gdy samo tworzenie obiektu jest kosztowne czasowo, a nie jest potrzebne wiele instancji.

Zasada działania:


Zazwyczaj tworzy się klasę zawierającą propercję lub polę pewnego typu. Klasa zewnętrzna posiada prywatny konstruktor i metodę zwracającą instancję obiektu z pola / propercji. Jeśli obiekt nie został wcześniej zainicjowany, to tworzy się instancję, która później jest zwracana przy każdym wywołaniu tej metody. Można użyć także klas statycznych, ale jest to odradzane ze względu na problemy z testowaniem i brak możliwości dziedziczenia.

Przykład:

Interfejs do zapisywania zmian do jakiegoś rejestru np logowanie wyjątków.

Przykład implementacyjny:

Poniższy singletonu wydaje się być optymalny ze względu na wydajność dla platformy .NET.




    public class ThreadSafeSingleton
    {
        private ThreadSafeSingleton()
        {
            
        }

        public static ThreadSafeSingleton Instance 
        {
            get { return NestedClass.instance; }
        }

        public void SayHello()
        {
            Console.WriteLine("How are you ?");
        }

        public class NestedClass
        {
            static NestedClass()
            {
            }

            internal static readonly ThreadSafeSingleton instance =
                new ThreadSafeSingleton();
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            var inst = ThreadSafeSingleton.Instance;
            inst.SayHello();

        }
    }


Prywatny konstruktor zabrania tworzenia obiektów klasy. Statyczna propercja gwarantuje, że przekazywana będzie jedna referencja przy każdym wywołaniu, natomiast dzięki statycznemu konstruktorowi klasy zagdnieżdżonej obiekt zostanie zainicjowany dopiero przy pierwszym jego wywołaniu (Lazy Loading). Pole readonly zapewnia bezpieczeństwo przy pracy wielowątkowej i jest to podejście szybsze od stosowania instrukcji lock.

Linki:

1.Readonly a thread safe 

niedziela, 1 lipca 2012

[Wzorce projektowe] Facade

Analogia z życia: 

Telewizja satelitarna, taka jak na przykład Cyfra+ w swej ofercie proponuje klientowi kilkaset kanałów. Często jednak zdarza się, że nie wszystkie z nich interesują klienta i co więcej nie potrzebuje do nich dostępu. W związku z tym może sobie wykupić pakiet, zawierający podzbiór wszystkich oferowanych kanałów.



Zastosowanie:

Kiedy mamy dostęp do pewnego API, z którego interesuje nas jedynie podzbiór usług, jakie ono oferuje. Fasadę stosujemy głównie, aby uprościć pewne API i wybrać z niego tą część, która nas interesuje. Może się też zdarzyć, że pewne API, które otrzymaliśmy zostało źle zaprojektowane - tu także do akcji wkracza wzorzec Fasady. Oczywiście nie jest powiedziane że Fasada dotyczy tylko jednego API, można także opakowywać wiele API w jeden interfejs dostosowany do bieżących potrzeb. Wraz z rozwojem programu fasada często będzie wymagała rozbudowywania.

Zasada działania:

Podobnie jak w przypadku Adaptera, przeważnie tworzy się klasę opakowującą pewne API, gdzie metody tej klasy wywołują metody z opakowywanego API.

Przykład:

Często tworzy się Fasady dla operacji I/O tak, aby zapis lub odczyt realizował się wywołaniem jednej metody.

Przykład implementacyjny:

Fasadę można utworzyć nawet dla dot Netowego API do pracy z ciągami znakowymi.

public class StringFacade
    {
        private string _str;

        public StringFacade(string  s)
        {
            _str = s;
        }

        public string Substring(int from, int to)
        {
            return _str.Substring(from, to - from);
        }

        public string Append(string s)
        {
            StringBuilder sb = new StringBuilder(_str);
            sb.Append(s);
            return sb.ToString();
        }
    }  


sobota, 30 czerwca 2012

[Wzorce projektowe] Adapter

Analogia z życia:

Gdy potrzebujemy podłączyć monitor z wyjściem DVI do wejścia VGA kupujemy adapter DVI -> VGA

Zastosowanie:

Klasa klienta oczekuje komponentu implementującego pewien interfejs. Mamy gotowy komponent, który chcemy użyć z poziomu klienta, natomiast nie implementuje on pożądanego przez klienta interfejsu. W tym celu wprowadza się adapter - dodatkową klasę, która implementuje interfejs wymagany przez klienta, a jednocześnie zawiera instancję komponentu. Wzorzec adaptera może być także użyty, gdy mając kilka mniejszych klas chcemy wystawić je jako całość implementującą wymagany interfejs.

Zasada działania:

Klient tworzy instancję adaptera pewnej klasy, wywołując jej metody. W tych wywołaniach kryją się wywołania metod komponentu opakowanego przez adapter. Projektując klasę klienta warto wykorzystywać interfejs zamiast konkretnej jego implementacji, co umożliwi otwarcie na nowe komponenty w przyszłości. Zastosowanie adaptera umożliwi także korzystanie z wielu adaptowanych implementacji.

Przykład:

IDataAdapter z ADO .NET

Przykład implementacyjny:

Klasa klienta:


    public class MyClient
    {
        public IMyAdapter Instance { get; set; }
    }

Interfejs adaptera:

public interface IMyAdapter
    {
        int CountElements();
        int NullElements();
        void ClearCollection();
        void ConsolePrint();
    } 

Udostępniane są pewne usługi. Konkretna implementacja:


 public class MyList<T> : IMyAdapter
    {
        private List<T> _commonList;

        public MyList(List<T> list)
        {
            _commonList = list;
        }

        public int CountElements()
        {
            return _commonList.Count;
        }

        public int NullElements()
        {
            /** pewne operacje **/
        }

        public void ClearCollection()
        {
            _commonList.Clear();
        }

        public void ConsolePrint()
        {
            /** pewne operacje **/
        }
Konkretne użycie:
class Program
    {
        public static IMyAdapter MyEnumerable { get; set; }

        static void Main(string[] args)
        {
            var list = new List<int?>();
            Random r = new Random();
            for (int i = 0; i < 20; i++)
            {
                int rnd = r.Next(100);
                if(rnd % 2 == 0)
                {
                    list.Add(rnd);
                }
                else
                {
                    list.Add(null);
                }
            }

            MyEnumerable = new MyList<int?>(list);
            Console.WriteLine(MyEnumerable.CountElements());
            Console.WriteLine(MyEnumerable.NullElements());
            MyEnumerable.ConsolePrint();
            MyEnumerable.ClearCollection();
            MyEnumerable.ConsolePrint();
        }
    }

[Matlab / Simulink] Przekazywanie danych z Simulinka do workspace podczas symulacji


W większości przypadków, dane z symulacji wystarczy przekazywać do workspace bloczkiem ToWorkspace, lub przez funkcję [x.y.t] = sim(...).



Podejście to ma jedną poważną wadę : cały wektor sygnału aktualizuje się dopiero po zakończeniu symulacji. Czasami zachodzi jednak potrzeba, by przesyłać dane na bieżąco, na przykład dla symulacji z czasem końcowym nieskończoność, gdzie użytkownik zmienia sygnały z GUI.

Aby na bieżąco aktualizować w workspace pewien sygnał, można wykorzystać bloczek Embedded Matlab Function





Wewnątrz wykorzystana zostanie funkcja assignin:


function y = fcn(u)
eml.extrinsic('assignin');
assignin('base','volume_work',u);
y = 1;  


 Instrukcja eml.extrinsic importuje funkcję do Embedded Matlab. Assignin przypisuje wejście bloczka (u) do zmiennej 'volume_work' z workspace o nazwie 'base' . Jest to nazwa domyślnego workspace w Matlabie.

Do komunikacji w drugą stronę można wykorzystać funkcję evalin.

Linki:
1. Mathworks - assignin
2. Mathworks - evalin