Przykłady użycia GoF Decorator Pattern dla IO

Przeczytałem w Wikipedii, że Decorator pattern jest używany dla . Net i Java IO.

Czy ktos moze wyjasnic jak to jest uzywane? A jakie są z tego korzyści z możliwego przykładu?

Jest przykład Windows forms na Wikipedii, ale chcę wiedzieć, jak to się dzieje z klasami Java IO .

Author: Levent Divilioglu, 2011-06-16

8 answers

InputStream jest klasą abstrakcyjną. Większość konkretnych realizacji jak BufferedInputStream, GzipInputStream, ObjectInputStream, itd. posiada konstruktor, który pobiera instancję tej samej klasy abstrakcyjnej. Jest to klucz rozpoznawania wzorca dekoratora (dotyczy to również konstruktorów biorących przykład tego samego interfejsu).

Gdy taki konstruktor jest używany, wszystkie metody będą delegować do zawiniętej instancji, ze zmianami w sposobie, w jaki metody zachowują się. Na przykład buforowanie strumienia w pamięci, dekompresja strumienia lub interpretacja strumienia w inny sposób. Niektóre mają nawet dodatkowe metody, które ostatecznie delegują dalej do zawiniętej instancji. Metody te dekorują zawiniętą instancję dodatkowym zachowaniem.

Załóżmy, że mamy kilka serializowanych obiektów Javy w pliku Gzipped i chcemy je szybko odczytać.

Najpierw otwórz inputstream z niego:

FileInputStream fis = new FileInputStream("/objects.gz");

Chcemy prędkość, więc buforujmy ją w pamięci:

BufferedInputStream bis = new BufferedInputStream(fis);

Plik jest gziped, więc musimy go ungzip:

GzipInputStream gis = new GzipInputStream(bis);

Musimy odserializować te obiekty Javy:

ObjectInputStream ois = new ObjectInputStream(gis);

Teraz możemy go wreszcie użyć:

SomeObject someObject = (SomeObject) ois.readObject();
// ...

Zaletą jest to, że masz dużo swobody w dekorowaniu strumienia za pomocą jednego lub więcej różnych dekoratorów do swoich potrzeb. To o wiele lepsze niż posiadanie jednej klasy dla każdej możliwej kombinacji, jak ObjectGzipBufferedFileInputStream, ObjectBufferedFileInputStream, GzipBufferedFileInputStream, ObjectGzipFileInputStream, ObjectFileInputStream, GzipFileInputStream, BufferedFileInputStream, itd.

Zauważ, że gdy masz zamiar zamknąć strumień, wystarczy zamknąć zewnętrzny dekorator. Będzie delegować close call aż do dołu.

ois.close();

Zobacz też:

 145
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:57

Przyjrzyjmy się komponentomDecorator wzorca przed przejściem do klas Java IO.

Tutaj wpisz opis obrazka

Dekorator wzór składa się z czterech elementów

  1. Component: komponent definiuje interfejs dla obiektów, które mogą mieć dodane dynamicznie
  2. ConcreteComponent: jest to po prostu implementacja komponentu interfejsu
  3. Dekorator: The dekorator ma odniesienie do komponentu , a także jest zgodny z interfejsem komponentu . Dekorator jest zasadniczo opakowaniem komponentu
  4. ConcreteDecorator: The ConcreteDecorator po prostu dodaje obowiązki do oryginalnego komponentu.

Wzór dekoratora może być użyty do rozszerzenia (udekorowania) funkcjonalności określonego obiektu statycznie, lub w niektórych przypadkach w czasie wykonywania, niezależnie innych instancji tej samej klasy, pod warunkiem, że pewne prace ziemne są wykonywane w czasie projektowania. Można to osiągnąć poprzez zaprojektowanie nowej klasy dekoratora, która owija oryginalną klasę.

Teraz mapujmy te pojęcia do java.io zajęcia pacakge.

Składnik:

InputStream :

Ta klasa abstrakcyjna jest klasą nadrzędną wszystkich klas reprezentujących strumień wejściowy bajtów.

Aplikacje, które muszą zdefiniować podklasę InputStream musi zawsze dostarczać metodę, która zwraca następny bajt wejścia.

public abstract int read() jest metodą abstrakcyjną.

ConcreteComponent:

FileInputStream :

Strumień plików pobiera bajty wejściowe z pliku w systemie plików. To, jakie pliki są dostępne, zależy od środowiska hosta.

FileInputStream jest przeznaczony do odczytu strumieni surowych bajtów, takich jak dane obrazu. Do czytania strumieni znaków rozważ użycie FileReader.

Przykłady wszystkich konkretnych komponentów InputStream:

AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream, 
InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, 
StringBufferInputStream

dekorator:

FilterInputStream :

FilterInputStream zawiera inny strumień wejściowy, który wykorzystuje jako podstawowe źródło danych, ewentualnie przekształcając dane po drodze lub zapewniając dodatkową funkcjonalność.

Należy pamiętać, że FilterInputStream implementuje InputStream => dekorator implementuje komponent jak pokazano w UML diagram .

public class FilterInputStream
extends InputStream

ConcreteDecorator:

BufferedInputStream

BufferedInputStream dodaje funkcjonalność do innego strumienia wejściowego-a mianowicie możliwość buforowania wejścia i obsługi metod oznaczania i resetowania.

Przykłady wszystkich Konkretyzatorów :

BufferedInputStream, CheckedInputStream, CipherInputStream, DataInputStream, 
DeflaterInputStream, DigestInputStream, InflaterInputStream, 
LineNumberInputStream, ProgressMonitorInputStream, PushbackInputStream

działający przykładowy kod:

Użyłem BufferedInputStream do odczytania każdego znaku słowa, które zostało zapisane w tekście plik a.txt

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("a.txt")));
while(bis.available()>0)
{
        char c = (char)bis.read();
        System.out.println("Char: "+c);;
}

Kiedy używać tego wzoru:

  1. obowiązki i zachowania obiektu powinny być dynamicznie dodawane / usuwane
  2. konkretne wdrożenia powinny być oddzielone od odpowiedzialności i zachowań
  3. gdy podklasowanie jest zbyt kosztowne, aby dynamicznie dodawać / usuwać obowiązki
 16
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

W. Net istnieje kilka dekoratorów strumieniowych, takich jak BufferedStream, CryptoStream, GzipStream itp. Wszystkie ozdabiają Stream klasę.

 8
Author: Alex Aza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-16 02:11:19

A-Wzór Dekoratora

A. 1 - przypadek użycia wzoru dekoratora

Wzór dekoratora jest używany do rozszerzenia funkcjonalności legacy bez zmiany klasy legacy. Powiedzmy, że mamy konkretną klasę, która implementuje interfejs. I musimy rozszerzyć funkcjonalność istniejącej metody jednak ponieważ istniejąca klasa i jej metody są już używane przez inne klasy, więc nie chcemy wprowadzać zmian w istniejących klasach. Ale musimy również rozszerzyć funkcjonalność na nowszej klasie, to jak rozwiązać ten problem?

1- We can't change the existing legacy code
2- We want to extend the functionality

Więc używamy wzoru dekoratora, zawijamy istniejącą klasę wewnątrz dekoratorów.

B-Podstawowy Wzór Dekoratora GoF Przykład

Tutaj mamy prosty interfejs i klasę implementacji / betonu. Interfejs ma jedną prostą metodę, którą jest {[12] } i zwraca String. Załóżmy, że istnieje wiele innych klas używających tej metody. Jeśli więc chcemy dokonać zmiany w implementacja / Klasa betonowa, wpłynie to na stary kod legacy. Chcemy go zmienić tylko na nowe klasy, więc używamy wzoru dekoratora.

Oto trywialny przykład wzoru projektowego gangu czterech dekoratorów;]}

B. 1-Pozdrawiam.java

public interface Greeter {
    String getMessageOfTheDay();
}

B. 2-BasicGreeter.java

public class BasicGreeter implements Greeter {

    @Override
    public String getMessageOfTheDay() {
        return "Welcome to my server";
    }

}

B. 3-Klasa Abstrakcyjnego Dekoratora: GreeterDecorator.java

public abstract class GreeterDecorator implements Greeter {

    protected Greeter greeter;

    public GreeterDecorator(Greeter greeter) {
        this.greeter = greeter;
    }

    public String getMessageOfTheDay() {
        return greeter.getMessageOfTheDay();
    }

}

B. 4-Klasa Dekoratora Betonu: StrangerDecorator.java

public class StrangerDecorator extends GreeterDecorator {

    public StrangerDecorator(Greeter greeter) {
        super(greeter);
    }

    @Override
    public String getMessageOfTheDay() {
        return "Hello Stranger " + super.getMessageOfTheDay();
    }

}

B. 5-Kod Demo: DecoratorDemo .java

public class DecoratorDemo {

    public static void main(String[] args) {
        Greeter greeter = new BasicGreeter();

        String motd = greeter.getMessageOfTheDay();

        System.out.println(motd);

        Greeter newGreeter = new StrangerDecorator(greeter);

        String newMotd = newGreeter.getMessageOfTheDay();

        System.out.println(newMotd);

        Greeter muchNewGreeter = new StrangerDecorator(new StrangerDecorator(greeter));

        String newestMotd = muchNewGreeter.getMessageOfTheDay();

        System.out.println(newestMotd);
    }

}
Spójrz na te przykłady. Abstrakcyjna klasa dekoratora jest potrzebna do owinięcia oryginalnego kontraktu i realizacji. Używając abstrakcyjnego dekoratora, możesz tworzyć nowsze dekoratory, ale w tym przykładzie, BasicGreeter {[40] } jest zawinięty wewnątrz abstrakcyjnego dekoratora i stworzyliśmy tylko nową klasę dekoratora, która jest StrangeGreeter . Informujemy, że zajęcia dekoratorskie mogą być używane jak pociąg, możemy owinąć dekoratora w środku inny dekorator czy ten sam. Funkcjonalność jest rozszerzalna, ale oryginalna klasa jest zachowana bez żadnych modyfikacji.

C - OutputStream Demo

Przyjrzyjmy się temu przykładowi. Chcemy napisać łańcuch do pliku z OutputStream. Oto kod demo;

C. 1-Przykładowe Demo OutputStream Do Zapisu Pliku

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class FileWriterDemo {

    public static void main(String[] args) throws IOException {
        File file = new File("./normal.txt");
        file.createNewFile();

        OutputStream oStream = new FileOutputStream(file);

        String content = "I love Commodore 64";

        oStream.write(content.getBytes());

        oStream.close();
    }

}

C. 2-wyjście dekoratora JSON: normalne.txt

Pojawi się nowy plik o nazwie " normal.txt " stworzony pod folder projektu i jego zawartość będzie;

I love Commodore 64

D - JSON OutputStream Decorator Demo

Teraz chcę utworzyć format wrappera JSON, który jest następujący;

{
    data: <data here>
}

Chcę, aby zawartość była zapisywana w prostym jednym polu w formacie JSON . Jak możemy osiągnąć ten cel? Jest wiele trywialnych sposobów. Jednak użyję GoF Decorator Pattern pisząc JSONDecorator , który rozszerzaOutputStream klasę Java;

D. 1-dekorator JSON dla OutputStream: JSONStream.java

public class JSONStream extends OutputStream {

    protected OutputStream outputStream;

    public JSONStream(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    @Override
    public void write(int b) throws IOException {
        outputStream.write(b);
    }

    @Override
    public void write(byte[] b) throws IOException {
        String content = new String(b);

        content = "{\r\n\tdata:\"" + content + "\"\r\n}";

        outputStream.write(content.getBytes());
    }

}

D. 2-JSON Decorator Demo: JSONDecoratorDemo.java

public class JSONDecoratorDemo {

    public static void main(String[] args) throws IOException {
        File file = new File("./json.txt");
        file.createNewFile();

        OutputStream oStream = new FileOutputStream(file);

        JSONStream js = new JSONStream(oStream);

        String content = "I love Commodore 64";

        js.write(content.getBytes());

        js.close();
        oStream.close();
    }

}

D. 3-Wyjście dekoratora JSON: json.txt

{
    data:"I love Commodore 64"
}

Właściwie, OutputStream sam wzór dekoratora jest abstrakcyjnym dekoratorem, a dekoratorem betonu jest klasa JSONStream .

 6
Author: Levent Divilioglu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-23 17:18:34

Wzór dekoratora jest używany w java.io klasy podczas manipulowania strumieniami wejścia/wyjścia (i to samo dotyczy czytelników i pisarzy).

Inputstream, bytearrayinputstream, stringbuilderinputstreams i tak dalej są elementami bazowymi. Filterinputstream jest klasą bazową dla klas decorator. Strumienie wejściowe filtrujące (takie jak strumień bufferedinput) mogą wykonywać dodatkowe czynności podczas odczytu strumieni lub zapisu do nich.

Są budowane przez hermetyzację strumienia i są strumieniami siebie.

new BufferedReader( new FileInputStream() ).readLine();

Nie przychodzi mi do głowy żadna klasa implementująca ten wzorzec w java.net, ale myślę, że powiedziano ci o tym pakiecie, ponieważ jest on silnie związany z java.io (socket.getInputStream na przykład).

Właściwie, oto kurs Z O ' relly (pdf na uwosh.edu | archive.org, slajdy na slideshare.net ), który wyjaśnia jak dekorator jest realizowany w java.io.

 4
Author: Snicolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-19 15:01:13

Jednym ze sposobów udekorowania strumienia wejściowego/wyjściowego jest zastosowanie do niego kompresji/dekompresji. Zobacz na przykład klasy w java.util.zip. Taki dekorowany strumień może być używany dokładnie tak samo jak "zwykły" strumień wejścia/wyjścia, z kompresją/dekompresją wykonywaną całkowicie przejrzyście.

 2
Author: Chris Jester-Young,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-16 02:08:27

Wzorzec dekoratora służy do dodawania funkcjonalności do istniejących obiektów, takich jak Klasa zdefiniowana w bibliotece. Następnie możesz "udekorować" go według swoich potrzeb. Jeśli jesteś zainteresowany dowiedzeniem się więcej o szablonach polecam "wzorce projektowe" Gang of Four.

 2
Author: Will Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-16 02:46:19

Cóż, mogę się spóźnić na imprezę, ale to pytanie nigdy się nie znudzi. Kluczowym punktem do zrozumienia dekorator jest to, że daje możliwość podłączenia obiektu do istniejącego obiektu do innego istniejącego obiektu i tak dalej. Popularne jest implementowanie tego wzoru w konstruktorze. Na przykład,

    Icecream ic = new RainbowTopUp(new ChocoTopUp(new Vanilla()));

Jeśli spojrzysz na diagram w Wikipedii, zobaczysz ConcreteComponenti Decoratordziedziczą z tej samej klasy nadrzędnej/interfejsu, Component. Oznacza to, że te dwie klasy mają te same metody implementacji.

Jednak w klasie Decorator zobaczysz strzałkę do Component, co oznacza, że używasz Component gdzieś w klasie Decorator {7]}. W tym przypadku używa się komponentu jako typu danych konstruktora w Dekoratorze . To jest wielka sztuczka. Bez tej sztuczki nie będzie można podłączyć nowego obiektu do istniejącego obiektu.

Po tym, można tworzy podklasy dziedziczące z klasy Decorator . Ponieważ wszystkie klasy mają ten sam root, każda pojedyncza klasa może swobodnie pluginować bez żadnego porządku.

 2
Author: kosalgeek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-10 11:30:58