Czy to jest Adapter?

1

LowRider to Adaptee?
PoliceCar to AdapterImplementation?
PrivilegedCar to Adapter?


package Adapter;

public interface PrivilegedCar {

    public void moveWithSiren();

    public void moveWithoutSiren();
}

package Adapter;

public class PoliceCar implements PrivilegedCar{

    private LowRider car;

    public PoliceCar(){
        this.car = new LowRider();
    }

    public void moveWithSiren(){
        System.out.println("*biu biu!* GETOUTA ROAD! *biu biu!* ");
    }

    public void moveWithoutSiren(){
        car.moveSlowlyInTheHood();
    }

}

package Adapter;

public class LowRider {

    public void moveSlowlyInTheHood(){
        System.out.println("havin a cool ride, dawg...");
    }

    public void runAwayFromPolice(){
        System.out.println("shieeeet... the cops! run!");
    }
}

package Adapter;

public class AppMain {
    public static void main(String[] args) {

        PoliceCar pc = new PoliceCar();
        pc.moveWithoutSiren();
        pc.moveWithSiren();

}

Jeśli tak to czy nie lepiej zrobić tak:


package Adapter;

public interface CityVehicle {

    default public void moveSlowlyInTheHood(){
        System.out.println("havin a cool ride, dawg...");
    }
}

package Adapter;

public interface PrivilegedCar {

    public void moveWithSiren();

    public void moveWithoutSiren();
}

package Adapter;

public class PoliceCar implements PrivilegedCar, CityVehicle{

    public PoliceCar(){

    }

    public void moveWithSiren(){
        System.out.println("*biu biu!* GETOUTA ROAD! *biu biu!* ");
    }

    public void moveWithoutSiren(){
        moveSlowlyInTheHood();
    }

}

package Adapter;

public class LowRider implements CityVehicle{

    public void runAwayFromPolice(){
        System.out.println("shieeeet... the cops! run!");
    }
}

package Adapter;

public class AppMain {
    public static void main(String[] args) {

        PoliceCar pc = new PoliceCar();
        pc.moveWithoutSiren();
        pc.moveWithSiren();

    }
}
2

imo to nie ma to zadnego sensu. co chcesz osiagnac?

4
katelx napisał(a):

imo to nie ma to zadnego sensu. co chcesz osiagnac?

Jak to co, on chce zastosować wzorce ;)

0

chcę osiągnąć implementację adaptera. :) Nie rozumiem po co robić adapter jak można postawić interfejs z domyślnymi metodami.

Tu chodzi o to, że LowRider to auto gangu i mają metody, które nie może mieć wóz policyjny PoliceCar poza 1 metodą.
Tę 1 metodę do wożenia się po dzielnicy chce mieć też wóz policyjny.

0

Załóżmy że masz biblioteke która pozwala holować samochody.

Twoje implementacje police car i low rider nie pozwalają na bycie holowanymi

Adapterem będzie więc klasa class TowingAdapter { .ctor(Vehicle vehicle ){} void AttachToTow(Tow tow) }

0

Od pewnego poziomu abstrakcji tłumaczenie obiektówki na zwierzątkach, czy przedmiotach codziennego użytku czy samochodach przestaje mieć sens (no chyba, że robisz grę albo coś innego, gdzie faktycznie występują zwierzęta, lodówki czy samochody jako obiekty dziedziny).

Lepiej wziąć to na przykładzie czegoś, co naprawdę ci się przyda. Np. chcesz wyświetlać komunikaty na stronie internetowej, ale nie wiesz jeszcze jak (czy może okienko alert, czy może wyświetlić to gdzieś w środku strony za pomocą jQuery, czy może komunikaty wyświetlać tylko w konsoli debuggerskiej itp.).

Ponieważ często będziesz wyświetlał komunikaty, potencjalna zmiana decyzji może cię kosztować zamianę np. 100 wywołań funkcji alert na adekwatne 100 wywołań funkcji console.log. Jest to bez sensu, więc potrzebne ci jest coś, co pozwala bardzo łatwo się przełączać pomiędzy róznymi implementacjami i nie uzależnia cię od detali technicznych. Więc możesz zrobić sobie 3 adaptery jQueryPrinter, alertPrinter i consolePrinter i każdy będzie miał taką samą metodę print:
(kod w JavaScript)


class jQueryPrinter {
   print(text) {
      $("#whatever").text(text); // wyswietla text za pomoca jQuery
   }
}

class AlertPrinter {
   print(text) {
      alert(text); // wyswietla okienko modalne z tekstem `text`
   }
}

class ConsolePrinter {
   print(text) {
      console.log(text); // wyswietla text w konsoli developerskiej
   }
}

a potem możesz operować na wyższym poziomie abstrakcji

const printer = new ConsolePrinter; // albo new AlertPrinter etc.

printer.print(2 + 2);
printer.print(1000 + 200 + 30 + 4);
printer.print('Hello World');

:)

2

@LukeJL: to co tu pokazałeś, to jest strategia, a nie adapter.

Adapter to taki kabelek, który z jednej strony ma HDMI, a z drugiej DVI. W programowaniu działa to dokładnie tak samo - pozwala połączyć jakiś obiekt X (stary monitor z DVI) z metodą, która przyjmuje obiekty określonego interfejsu I (czyli HDMI). Musisz w tym celu ten swój obiekt X opakować w obiekt Adapter, który będzie także implementował interfejs I (czyli kabelek konwertujący DVI na HDMI). Metody wymagane przez I w implementacji Adaptera będą w praktyce wołały metody obiektu X.

Ogólnie polecam przeczytać Head first design patterns.

2

To co chcesz osiągnąć to jakaś forma substytucji jednego typu innym i zadziałało by to w językach z tzw. kaczym typowaniem (duck typing - jeżeli coś kwacze jak kaczka i pływa jak kaczka to jest to kaczka, choć w rzeczywistości może to być coś zupełnie innego). Wzorzec adaptera służy do tłumaczenia, adaptacji, jednego interfejsu na inny. W twoim przypadku mogło by to wyglądać tak:

class LowRiderToPoliceCarAdapter implements PrivilegedCar{

    private LowRider lowRider;

    public LowRiderToPoliceCarAdapter(LowRider lowRider){
        this.lowRider = lowRider;
    }

    public void moveWithSiren(){
            // pytanie jak lowRIder ma udawać wóz policyjny?
        }

        public void moveWithoutSiren(){
            lowRider.moveSlowlyInTheHood();
        }
}

I teraz masz coś co pozwala na adaptację LowRidera na samochód policyjny.

0

Jak czytam teraz definicje adaptera i strategii z książki GoF tak na szybko to wydaje mi się, że różnica jest głównie w przeznaczeniu "do czego ta klasa może służyć" * a niekoniecznie w implementacji - w obydwu wzorcach mamy rzecz A, która chce używać jakichś niekompatybilnych interfejsów X oraz Y w ten sam sposób, więc korzysta z jakiegoś wrappera, który udostępnia jednolity interfejs B.

Ja nie widzę różnicy, chociaż możliwe, że jest.

* Z tego, co wyczytałem i jak to rozumiem, to przy adapterze zwykle mamy już gotowy jakiś interfejs, którego używamy i tylko jeden z obiektów jest “czarną owcą” i chcemy go przyrównać do pionu (czyli trochę jak UK a Europa - gniazdka inne, mile, ruch lewostronny itp.). Natomiast przy strategii startujemy od zera i żaden obiekt nie zachowuje się standardowo (czyli trochę jak XKCD 927: https://xkcd.com/927/ ).
Przynajmniej tak to rozumiem.

0

@LukeJL: w adapterze masz dwie rzeczy - kod operujący na obiektach implementujących dany interfejs oraz obiekt, który tego interfejsu nie implementuje. Dlatego piszesz adapter, który opakowuje ten obiekt do istniejącego kodu.
W strategii masz zestaw różnych algorytmów o wspólnym interfejsie. Ok, możesz napisać strategię, która będzie przy okazji adapterem (bo opakuje jakąś istniejącą bibliotekę, aby realizowała cele strategii), ale strategia nadal będzie jakby poziom wyżej w abstrakcji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0