Szukaj…


Wzorzec adaptera (PHP)

Przykład ze świata rzeczywistego z wykorzystaniem eksperymentu naukowego, w którym pewne procedury są wykonywane na różnych typach tkanek. Klasa zawiera domyślnie dwie funkcje pobierania tkanki lub rutyny osobno. W późniejszej wersji zaadaptowaliśmy ją za pomocą nowej klasy, aby dodać funkcję, która otrzymuje oba. Oznacza to, że nie edytowaliśmy oryginalnego kodu i dlatego nie ponosimy ryzyka zepsucia naszej istniejącej klasy (i bez ponownego testowania).

class Experiment {
    private $routine;
    private $tissue;
    function __construct($routine_in, $tissue_in) {
        $this->routine = $routine_in;
        $this->tissue  = $tissue_in;
    }
    function getRoutine() {
        return $this->routine;
    }
    function getTissue() {
        return $this->tissue;
    }
}

class ExperimentAdapter {
    private $experiment;
    function __construct(Experiment $experiment_in) {
        $this->experiment = $experiment_in;
    }
    function getRoutineAndTissue() {
        return $this->experiment->getTissue().' ('. $this->experiment->getRoutine().')';
    }
}

Adapter (Java)

Załóżmy, że w twojej obecnej bazie kodu istnieje interfejs MyLogger :

interface MyLogger {
    void logMessage(String message);
    void logException(Throwable exception);
}

Powiedzmy, że utworzyłeś kilka konkretnych implementacji takich, jak MyFileLogger i MyConsoleLogger .

Zdecydowałeś, że chcesz użyć platformy do kontrolowania łączności Bluetooth Twojej aplikacji. Ta struktura zawiera BluetoothManager z następującym konstruktorem:

class BluetoothManager {
    private FrameworkLogger logger;

    public BluetoothManager(FrameworkLogger logger) {
        this.logger = logger;
    }
}

BluetoothManager akceptuje także rejestrator, co jest świetne! Oczekuje jednak, że logger, którego interfejs został zdefiniowany przez platformę, użył przeciążenia metody zamiast nazwać swoje funkcje inaczej:

interface FrameworkLogger {
    void log(String message);
    void log(Throwable exception);
}

Masz już kilka implementacji MyLogger , których chciałbyś użyć ponownie, ale nie pasują one do interfejsu FrameworkLogger . Tutaj pojawia się wzór projektowy adaptera:

class FrameworkLoggerAdapter implements FrameworkLogger {
    private MyLogger logger;

    public FrameworkLoggerAdapter(MyLogger logger) {
        this.logger = logger;
    }

    @Override
    public void log(String message) {
        this.logger.logMessage(message);
    }

    @Override
    public void log(Throwable exception) {
        this.logger.logException(exception);
    }
}

Poprzez zdefiniowanie klasy adaptera, która implementuje interfejs FrameworkLogger i akceptuje implementację MyLogger funkcjonalność może być mapowana między różnymi interfejsami. Teraz można korzystać z BluetoothManager we wszystkich implementacjach MyLogger takich jak:

FrameworkLogger fileLogger = new FrameworkLoggerAdapter(new MyFileLogger());
BluetoothManager manager = new BluetoothManager(fileLogger);

FrameworkLogger consoleLogger = new FrameworkLoggerAdapter(new MyConsoleLogger());
BluetoothManager manager2 = new BluetoothManager(consoleLogger);

Przykład Java

Świetny istniejący przykład wzorca adaptera można znaleźć w klasach SWT MouseListener i MouseAdapter .

Interfejs MouseListener wygląda następująco:

public interface MouseListener extends SWTEventListener {
    public void mouseDoubleClick(MouseEvent e);
    public void mouseDown(MouseEvent e);
    public void mouseUp(MouseEvent e);
}

Teraz wyobraź sobie scenariusz, w którym budujesz interfejs użytkownika i dodajesz te nasłuchiwania, ale przez większość czasu nie przejmujesz się niczym innym, niż kiedy jedno kliknięcie (mouseUp). Nie chcesz ciągle tworzyć pustych implementacji:

obj.addMouseListener(new MouseListener() {

    @Override
    public void mouseDoubleClick(MouseEvent e) {
    }

    @Override
    public void mouseDown(MouseEvent e) {
    }

    @Override
    public void mouseUp(MouseEvent e) {
        // Do the things
    }

});

Zamiast tego możemy użyć MouseAdapter:

public abstract class MouseAdapter implements MouseListener {
    public void mouseDoubleClick(MouseEvent e) { }
    public void mouseDown(MouseEvent e) { }
    public void mouseUp(MouseEvent e) { }
}

Zapewniając puste, domyślne implementacje, możemy zastąpić tylko te metody, na których nam zależy. Zgodnie z powyższym przykładem:

obj.addMouseListener(new MouseAdapter() {

    @Override
    public void mouseUp(MouseEvent e) {
        // Do the things
    }

});

Adapter (UML i przykładowa sytuacja)

Aby uczynić użycie wzorca adaptera i rodzaj sytuacji, kiedy można go zastosować, można sobie wyobrazić, podając tutaj mały, prosty i bardzo konkretny przykład. Nie będzie tu kodu, tylko UML i opis przykładowej sytuacji i jej problemu. Trzeba przyznać, że treść UML jest napisana jak Java. (Cóż, w tekście podpowiedzi było napisane: „Dobre przykłady to w większości kod”. Myślę, że wzorce projektowe są na tyle abstrakcyjne, że można je również wprowadzić w inny sposób.)

Ogólnie wzorzec adaptera jest odpowiednim rozwiązaniem w sytuacji, gdy masz niekompatybilne interfejsy i żadnego z nich nie można bezpośrednio przepisać.

Wyobraź sobie, że prowadzisz niezłą usługę dostarczania pizzy. Klienci mogą zamawiać online na twojej stronie internetowej, a ty masz mały system korzystający z klasycznej Pizza do reprezentowania twoich pizz i obliczania rachunków, raportów podatkowych i innych. Cena twoich pizzy jest podawana jako jedna liczba całkowita reprezentująca cenę w centach (wybranej waluty).

wprowadź opis zdjęcia tutaj

Twoja usługa dostawy działa świetnie, ale w pewnym momencie nie możesz samodzielnie poradzić sobie z rosnącą liczbą klientów, ale nadal chcesz się rozwijać. Decydujesz się na dodanie swojej pizzy do menu dużej usługi dostarczania meta online. Oferują wiele różnych posiłków - nie tylko pizze - więc ich system w większym stopniu korzysta z abstrakcji i ma interfejs IMeal reprezentujący posiłki dostarczane wraz z klasą MoneyAmount reprezentującą pieniądze.

wprowadź opis zdjęcia tutaj

MoneyAmount składa się z dwóch liczb całkowitych jako danych wejściowych, jednej dla kwoty (lub jakiejś losowej waluty) przed przecinkiem i jednej dla kwoty w MoneyAmount od 0 do 99 po przecinku;

wprowadź opis zdjęcia tutaj

Ze względu na fakt, że cena Twojej Pizza jest jedną liczbą całkowitą reprezentującą całkowitą cenę w IMeal (> 99), nie jest kompatybilna z IMeal . W tym momencie pojawia się wzorzec adaptera: jeśli zmiana własnego systemu lub utworzenie nowego wymagałoby zbyt dużego wysiłku i konieczne będzie zaimplementowanie niezgodnego interfejsu, może być konieczne zastosowanie wzoru adaptera.

Istnieją dwa sposoby zastosowania wzorca: adapter klasy i adapter obiektu.

Oba mają wspólną cechę, że adapter ( PizzaAdapter ) działa jako swego rodzaju tłumacz między nowym interfejsem a adapttee ( Pizza w tym przykładzie). Adapter implementuje nowy interfejs ( IMeal ), a następnie dziedziczy po Pizza i konwertuje własną cenę z jednej liczby całkowitej na dwie (adapter klasy)

wprowadź opis zdjęcia tutaj

lub ma obiekt typu Pizza jako atrybut i konwertuje wartości tego (adapter obiektu).

wprowadź opis zdjęcia tutaj

Stosując wzorzec adaptera, będziesz w pewien sposób „tłumaczyć” między niekompatybilnymi interfejsami.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow