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