piątek, 6 lipca 2012

[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

czwartek, 5 stycznia 2012

[WPF] Wycinanie z WriteableBitmap

Temat:
Jak wycinać dowolny prostokąt z obrazka reprezentowanego przez WriteableBitmap.

Przygotowałem własną ExtensionMethod dla klasy WriteableBitmap, która korzystając z kodu niezarządzanego wybiera interesujący nas zbiór pikseli i zwraca nową bitmapę. ExtensionMethod działa jako dodatkowa metoda dla istniejącej już klasy. Można jej używać w zasięgu jednego namespace i musi być ona statyczną metoda statycznej klasy przyjmującą za pierwszy argument typ na rzecz którego ma być wywoływana poprzedzony this.


1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public static class Extensions
    {
        public static WriteableBitmap Split(this WriteableBitmap wb, int left, int top, int width, int height)
        {
            if(left + width > wb.PixelWidth || top + height > wb.PixelHeight)
                throw new ArgumentException("Out of picture bounds !");

            WriteableBitmap split = new WriteableBitmap(width, height, wb.DpiX, wb.DpiY, wb.Format, wb.Palette);

            var pixelLength = wb.Format.BitsPerPixel / 8;
            var stride = pixelLength * wb.PixelWidth;
            var data = new byte[pixelLength * width * height];         
            int k = 0;
                        
            unsafe
            {
                var tab = (byte*)wb.BackBuffer;

                int index = 0;
                for (int j = 0; j < wb.Height; j++)
                {
                    for (int i = 0; i < wb.Width; i++)
                    {

                        if (i > left && i <= left + width && j > top && j <= top + height)
                        {
                            index = j * (pixelLength * (int)wb.PixelWidth) + i * pixelLength;
                            data[k++] = (byte)tab[index];
                            data[k++] = (byte)tab[index + 1];
                            data[k++] = (byte)tab[index + 2];
                            data[k++] = (byte)tab[index + 3];
                        }
                    }
                }
            }


            var rect = new Int32Rect(0, 0, width, height);
            split.WritePixels(rect, data, width * pixelLength , 0);

            return split;
        }
    }

Przykład użycia metody dla obrazka, który jest itemem dodanym do projektu:

1
2
3
4
5
6
7
8
9
private void LoadImage()
        {
            var uri = new Uri("pack://siteoforigin:,,,/vlepa.jpg");
            BitmapSource bs = new BitmapImage(uri);
            image = new WriteableBitmap(bs);

          
            WriteableBitmap small = image.Split(50,50,200,200);
        }

Aby móc kompilować kod niezarządzany (blok unsafe), należy w VS wejść w Properties projektu i w zakładce Build wybrać Allow unsafe code.

Kompilator : VS 2010