Kihagyás

Tervezési minták II

Feladat - Halmazok

(\(\mathbb{N}\)) Halmaz tárolásához több stratégia létezik

  • Nem ismert a felsőkorlát
    • Sorozat
  • Ismert a felsőkorlát
    • max + 1 hosszú bool tömb
    • Index a számot reprezentálja, a logika érték határozza meg, hogy benne van-e

A használónak nem dolga tudni, hogy a viselkedést milyen implementáció valósítja meg

Halmaz reprezentációja

1. megoldás - Típus interfész

  • A két osztály funkcióját ellátja
  • Nincsenek rejtve, és a futásidő előtt el kel dönteni, melyik legyen használva

2. megoldás - Ősosztály reprezentációval

  • Az ősosztály adattagként tartja magában az interface-t
  • Az alosztályok rejtve maradnak, futáskor elég választani

Híd (bridge) tervezési minta

Híd tervezési minta

A típust biztosító osztályról leválasztjuk annak reprezentációját, hogy azt rugalmasan, furási időben választhassuk ki.

Sorozat megvalósítása

class SequenceSet : ISetRepr
{
    private List<int> seq = new ();
    public SequenceSet() { seq.Clear(); }
    public void SetEmpty() { seq.Clear(); }
    public void Insert(int e) { if (!seq.Contains(e)) seq.Add(e); }
    public void Remove(int e) { seq.RemoveAt(e); }
    public bool Empty() { return seq.Count==0;}
    public int Select() { return seq[0]; }
    public bool In(int e) { return seq.Contains(e); }
}

List műveletekkel van megoldva

Tömb megvalósítása

class ArraySet : ISetRepr
{
    private bool[] vect;
    private int size;
    public ArraySet(int n)
    {
        vect = new bool[n+1];
        for (int i = 0; i <= n; ++i) vect[i] = false;
        size = 0;
    }
    public void SetEmpty()
    {
        for (int i = 0; i < vect.Length; ++i) vect[i] = false;
        size = 0;
    }
    public void Insert(int e)
    {
        if (e < 0 || e >= vect.Length) throw new IllegalElementException(e);
        if (!vect[e])
        { 
            vect[e] = true; 
            ++size; 
        }
    }
    public void Remove(int e)
    {
        if (e < 0 || e >= vect.Length) throw new IllegalElementException(e);
        if (vect[e]) 
        { 
            vect[e] = false; 
            --size;
        }
    }
    public int Select()
    {
        int e;
        for (e = 0; !vect[e]; ++e);
        return e;
    }
    public bool Empty() 
    { 
        return size == 0; 
    }
    public bool In(int e)
    {
        if (e < 0 || e >= vect.Length) throw new IllegalElementException(e);
        return vect[e];
    }
}

Tervezési minták hasonlósága

Jellemzően a tevékenység legrugalmasabb leírásához több, metódusba szétosztva definiáljuk.

Ehhez az objektum befecskendezése(injection) használatos.

Tervezési minták hasonlósága

Hasonlóságok

  • Stratégia (Strategy)
    • ClassB-nek a B() metódusa felhasználja a ClassA-t teljesítő valamelyik osztály A() metódusát
  • Látogató (Observer)
    • ClassB alosztályiba származtatott B() metódus függ egy ClassA ősű objektumtól
  • Híd (Bridge)
    • ClassB típus megvalósítását a ClassB-be komponált objektum szolgáltatja

Felelősség átruházás módja

Objektum befecskendezés

Objektum befecskendezés

Az objektum metódusa egy másik objektum metódusát hívja

Származtatás

Származtatás

Az objektum metódusa az ősosztály nem felülírt metódussát hívja

Osztálysablon

Osztálysablon

Az objektum metódusa a sablonparaméterében kapott osztály metódusát hívja

Sekély és mély másolás

Szabványos megoldás: a lemásolandó objektum osztályában megvalósítjuk az ICloneable interfész Clone() metódusát, amelynek másolatot kell készíteni az objektumról.

Hátránya: a Clone() metódus object-tel tér vissza, amelyet típuskényszeríteni(kasztolni) kell.

Előfordulhat egyes nyelvekben, hogy aféle másoló konstruktora legyen egy objektumnak, ami a megadott objektum adattagjaival tölti fel az új példányt.

Felsoroló (iterator) tervezési minta

A gyűjtemény elemeinek bejárását egy önálló objektum (felsoroló) végzi, amely eléri a felsorolandó gyűjteményt (vagy úgy hivatkozik rá, hogy közben nem módosítja, vagy előbb készít róla egy másolatot, és utána ezt használja).

A felsoroló objektumot a felsorolni kívánt gyűjtemény hozza létre (akár többet is), de nem feltétlenül tartja nyilván ezeket.

Az iterátor(vagy enumerátor) létrehozása a gyűjtemény felelőssége!

Előnye, hogy a gyűjtemény nyilván tarthatja az őt bejáró iterátorokat, akár más viselkedést is felvehet.

Mondjuk nem hagy törölni, ha éppen felsorják.

Felsoroló tervezési minta

Gyártófüggvény (factory method) tervezési minta

Factory method

Az osztály nem tudja előre megjüsolni, hogy milyen típusú objektumok kell létrehozzon, ezért átruházza az alosztályaira.

ArraySet Felsorolója

public class ArraySetEnor : MyEnumerator
{
    private readonly ArraySet s;
    private int ind;
    public ArraySetEnor(ArraySet h) { s = h; }
    private void FindNext()
    {
        for (++ind; ind < s.vect.Length && !s.vect[ind]; ++ind) ;
    }
    public override void First() { ind = -1; FindNext(); }
    public override void Next() { FindNext(); }
    public override bool End() { return ind==s.vect.Length; }
    public override int Current() { return ind; }
} 

SequenceSet Felsorolója

public class SequenceSetEnor : MyEnumerator
{
    private readonly SequenceSet s;
    private int ind;
    public SequenceSetEnor(SequenceSet h) { s = h; }
    public override void First() { ind = 0; }
    public override void Next() { ++ind; }
    public override bool End() { return ind == s.seq.Count; }
    public override int Current(){ return s.seq[ind]; }
}

Generikus

A típust úgy nevezett típus-paraméterrel jelöljük, ezzel általánosítva annak típusát.

Fordítási időben osztályként példányosodik az osztálysablon, futási időben objektum formájában példányosogik az osztály.

Generikusok UML-ben