Illesztő programtervezési minta

A Wikipédiából, a szabad enciklopédiából

A számítástudományban az illesztő programtervezési minta (gyakran becsomagoló minta vagy csak egyszerűen csomagoló vagy illesztő) (angolul Adapter) egy programtervezési minta, amely lefordítja az egyik osztály interfészét egy kompatibilis másik interfészre.[1] Egy illesztő lehetővé teszi olyan osztályok együttműködését, amelyek az inkompatibilis interfészeik miatt normálisan nem tudnának együttműködni, mindezt oly módon, hogy interfészt nyújt a kliensek számára, míg ő maga az eredeti interfészt használja. Az illesztő interfész hívásokat lefordítja az eredeti interfész hívásokra, tipikusan kis kód mennyiségű kód segítségével. Az illesztő felelős továbbá az adat megfelelő formátumba való áttranszformálásáért is. Például ha több boolean értéket tárolunk egyszerű integer-ként (azaz flag-ekként), de a kliens önálló boolean értékeket igényel, az illesztő felelős a megfelelő értékek előállításáért az integer értékből és vissza. Egy másik példa a dátum formátumok transzformációi (pl. YYYYMMDD-t MM/DD/YYYY-é vagy DD/MM/YYYY-é alakítás).

Definíció[szerkesztés | forrásszöveg szerkesztése]

Az illesztő segíti két nem kompatibilis interfész együttműködését. Ez az illesztő valós életbeli definíciója. Az illesztő tervezési mintát akkor használjuk, amikor két különböző osztály nem kompatibilis interfészét szeretnénk együttműködésre bírni. Az elnevezés pusztán ennyit jelent. Az interfészek lehetnek nem kompatibilisek, de a belső funkcionalitás illeszkedik az igényekhez. Az illesztő minta lehetővé teszi a másként nem kompatibilis osztályok együttműködését azáltal, hogy konvertálja az egyik osztály interfészét a kliens által elvárt másik interfészébe.

A Struktúra[szerkesztés | forrásszöveg szerkesztése]

Kétfajta illesztő minta lehetséges:[1]

Objektum illesztő minta[szerkesztés | forrásszöveg szerkesztése]

Ebben a típusú illesztő mintában az illesztő tartalmazza annak az osztálynak egy példányát, amelyet becsomagol. Ebben a helyzetben az illesztő hívásokat indít a becsomagolt példány objektum felé.

Az objektum illesztő minta UML-ben. Az illesztő elrejti az illesztett interfészét a kliens elöl.
Az objektum illesztő minta LePUS3-ban.

Osztály illesztő minta[szerkesztés | forrásszöveg szerkesztése]

Ez a fajta illesztő több többalakú interfészt használ, hogy célját elérje. Az illesztő úgy készül, hogy megvalósítja vagy örökli mind várt interfészt, mind a már korábban létező interfészt.Tipikusan a várt interfész egy sima interfész osztály, különösen olyan programozási nyelvekben, mint a Java, amely nem támogatja a többszörös öröklődést[1].

Az osztály illesztő minta UML-ben
Fájl:Adapter(Class) pattern in LePUS3.png
Az osztály illesztő minta LePUS3-ban

Az illesztő minta azokban az esetek hasznos, amikor egy már létező osztály biztosítja a számunkra szükséges néhány vagy az összes szolgáltatást, de nem használja azt, az interfészt, amire szükségünk van. Egy valós életből vett példa: egy illesztő, amely egy XML dokumentum DOM interfészét alakítja át egy megjeleníthető fa struktúrára. A cikk alján lévő listában megadjuk azokat a oktatási célzatú hivatkozásokat, amelyek az illesztő programtervezési mintát használják.

A futásidejű illesztő minta további formái[szerkesztés | forrásszöveg szerkesztése]

A futásidejű illesztő mintának még a további formái ismertek:

Tegyük fel, hogy a classA-nak kell ellátnia a classB-t adatokkal pl. String adattal. Erre egy fordítási idejű megoldás a következő:

classB.setStringData(classA.getStringData());

Habár feltételezzük, hogy a string formátumú adat megváltoztatható. Egy fordítási idejű megoldás az öröklődés használatára:

Format1ClassA extends ClassA {
   public String getStringData() {
      return format(toString());
   }
}

és esetleg elkészíti a korrekt formátumú objektumot futásidőben a Gyár programtervezési minta segítségével.

Egy megoldás illesztők használatával a következő:

(i) Definiáljunk egy köztes "szolgáltató" interfészt, és írjunk meg a szolgáltató implementációját, amely becsomagolja az adat forrást. Pl. ebben a példában ClassA, amely kiírja az adatokat a megfelelő formátumban:

public interface StringProvider {
    public String getStringData();
}
 
public class ClassAFormat1 implements StringProvider {
    private ClassA classA = null;
 
    public ClassAFormat1(final ClassA A) {
        classA = A;
    }
 
    public String getStringData() {
        return format(classA.toString());
    }
}

(ii) Írjunk egy illesztő osztályt, amely visszatér a szolgáltató egy speciális megvalósításával:

public class ClassAFormat1Adapter extends Adapter {
   public Object adapt(final Object OBJECT) {
      return new ClassAFormat1((ClassA) OBJECT);
   }
}

(iii) Regisztráljuk az Adapter-t a globális registry-ben, hogy az Adapter lookup-olni tudjon futásidőben:

AdapterFactory.getInstance().registerAdapter(ClassA.class, ClassAFormat1Adapter.class, "format1");

(iv) Abban az esetben, ha adatot szeretnénk küldeni a ClassA-ból a ClassB-ba, írjuk a következőt:

Adapter adapter = AdapterFactory.getInstance().getAdapterFromTo(ClassA.class,
    StringProvider.class, "format1");
StringProvider provider = (StringProvider) adapter.adapt(classA);
String string = provider.getStringData();
classB.setStringData(string);

vagy rövidebben:

classB.setStringData(((StringProvider) AdapterFactory.getInstance().getAdapterFromTo(ClassA.class,
    StringProvider.class, "format1").adapt(classA)).getStringData());

(v) Akkor előnyösebb, ha az adatátvitelhez a 2. formátum az elvárt: meg kell keresni hozzá a különböző illesztőt/szolgáltatót:

Adapter adapter = AdapterFactory.getInstance().getAdapterFromTo(ClassA.class,
    StringProvider.class, "format2");

(vi) Ha az elvárt viselkedés az, hogy a kimenet megkapható legyen a ClassA-ból, pl. képi adatként ClassC formájába:

Adapter adapter = AdapterFactory.getInstance().getAdapterFromTo(ClassA.class, ImageProvider.class,
    "format1");
ImageProvider provider = (ImageProvider) adapter.adapt(classA);
classC.setImage(provider.getImage());

(vii) Ezzel a módszerrel az illesztők és szolgáltatók használata biztosítja a ClassB-n és ClassC-n keresztül a többszörös "nézeteket" a ClassA-on az osztály hierarchia módosítása nélkül. Általánosan szólva így egy mechanizmus engedélyezhető önkényes adatfolyamokra az objektumok között, ami így utólagosan alkalmazható egy létező objektum hierarchiára.

Az illesztő minta megvalósítása[szerkesztés | forrásszöveg szerkesztése]

Az illesztő minta megvalósításakor az egyértelműség kedvéért használjuk az [AdapteeClassName]To[Interface]Adapter osztály neveket, pl. DAOToProviderAdapter. Kell egy konstruktor metódus, aminek az illesztendő osztály változó paramétere. Ezt a paramétert fogja tovább adni a AdapteeClassName]To[Interface]Adapter példány változónak.

public class AdapteeToClientAdapter implements Client {
 
    private final Adaptee instance;
 
    public AdapteeToClientAdapter(final Adaptee instance) {
         this.instance = instance;
    }
 
    @Override
    public void clientMethod() {
       // call Adaptee's method(s) to implement Client's clientMethod
    }
 
}

Az illesztő minta C# megvalósítása[szerkesztés | forrásszöveg szerkesztése]

A következő példa az illesztő minta egy C# megvalósítást mutatja be[2]. Ebben a példában IEmployee objektumok gyűjteményét (collection) készítjük el. Habár az employee (alkalmazott) megvalósítja az IEmployee-t, így természetesen hozzáadható a listához, de a Consultant (tanácsadó) osztály nem kötődik az IEmployee-hoz. Azért, hogy ez az osztály hozzáadható legyen ugyanahhoz a listához, el kell készíteni egy EmployeeAdapter nevű illesztő osztályt, amely becsomagolja a Consultant osztályt. Ez használja az IEmployee interfészt, ezáltal lehetővé téve, hogy hozzáadható legyen ugyanahhoz a listához.

using System.Collections.Generic;    
 
class Program
{
    static void Main(string[] args)
    {
        List<IEmployee> list = new List<IEmployee>();
        list.Add(new Employee("Tom"));
        list.Add(new Employee("Jerry"));
        list.Add(new ConsultantToEmployeeAdapter("Bruno"));  //consultant from existing class
        ShowHappiness(list);
    }
 
    //*** Code below from the existing library does not need to be changed ***
    static void ShowHappiness(List<IEmployee> list)
    {
        foreach (IEmployee i in list)
            i.ShowHappiness();
    }
}
 
//from the existing library, does not need to be changed
public interface IEmployee
{
    void ShowHappiness();
}
 
public class Employee : IEmployee
{
    private string name;
 
    public Employee(string name)
    {
        this.name = name;
    }
 
    void IEmployee.ShowHappiness()
    {
        Console.WriteLine("Employee " + this.name + " showed happiness");
    }
}
 
//existing class does not need to be changed
public class Consultant
{
    private string name;
 
    public Consultant(string name)
    {
        this.name = name;
    }
 
    protected void ShowSmile()
    {
        Console.WriteLine("Consultant " + this.name + " showed smile");
    }
}
 
public class ConsultantToEmployeeAdapter: Consultant, IEmployee
{
    public ConsultantToEmployeeAdapter(string name) : base(name)
    {
    }
 
    void IEmployee.ShowHappiness()
    {
        base.ShowSmile();  //call the parent Consultant class
    }
}

Kapcsolódó szócikkek[szerkesztés | forrásszöveg szerkesztése]

  • Delegálás, fontos az objektum illesztő mintához.
  • Dependency inversion principle (magyarul függőség megfordítás), which can be thought of as applying the Adapter pattern, when the high-level class defines their own (adapter) interface to the low-level module (implemented by an Adaptee class).
  • Csomagoló függvények

Jegyzetek[szerkesztés | forrásszöveg szerkesztése]

  1. ^ a b c (2004.) „Head First Design Patterns” (paperback), 244. o, Kiadó: O'Reilly Media. Hozzáférés ideje: 2013. április 30.  
  2. Thank you to devshed for providing the original version of this code under open license

További információk[szerkesztés | forrásszöveg szerkesztése]

Sablon:Commons category

A(z) Sablon:Nyelv neve/Adapter implementations in various languages Wikikönyvekben
további információk találhatók
Adapter témában.

Sablon:Design Patterns Patterns

Fordítás[szerkesztés | forrásszöveg szerkesztése]

Ez a szócikk részben vagy egészben az Adapter pattern című angol Wikipédia-szócikk ezen változatának fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel.