JavaRush /Java Blogu /Random-AZ /Java-da dizayn nümunələri
Viacheslav
Səviyyə

Java-da dizayn nümunələri

Qrupda dərc edilmişdir
Nümunələr və ya dizayn nümunələri tərtibatçının işinin tez-tez nəzərdən qaçırılan hissəsidir və kodun saxlanmasını və yeni tələblərə uyğunlaşdırılmasını çətinləşdirir. Bunun nə olduğuna və JDK-da necə istifadə edildiyinə baxmağı təklif edirəm. Təbii ki, bu və ya digər formada olan bütün əsas naxışlar uzun müddətdir ətrafımızdadır. Gəlin onları bu baxışda görək.
Java-da Dizayn Nümunələri - 1
Məzmun:

Şablonlar

Vakansiyalarda ən çox yayılmış tələblərdən biri “Nümunələri bilmək”dir. Əvvəlcə sadə bir suala cavab verməyə dəyər - "Dizayn nümunəsi nədir?" Pattern ingilis dilindən “şablon” kimi tərcümə olunur. Yəni bu, müəyyən bir nümunədir ki, ona uyğun olaraq nəsə edirik. Proqramlaşdırmada da belədir. Ümumi problemlərin həlli üçün müəyyən edilmiş ən yaxşı təcrübələr və yanaşmalar mövcuddur. Hər bir proqramçı memardır. Yalnız bir neçə sinif və ya hətta bir sinif yaratsanız belə, kodun dəyişən tələblər altında nə qədər davam edə biləcəyi, başqaları tərəfindən istifadə edilməsinin nə qədər rahat olması sizdən asılıdır. Şablonlar haqqında biliklər burada kömək edəcək, çünki... Bu, kodu yenidən yazmadan ən yaxşı şəkildə necə yazmağı tez başa düşməyə imkan verəcəkdir. Bildiyiniz kimi, proqramçılar tənbəl insanlardır və bir şeyi dərhal yaxşı yazmaq onu bir neçə dəfə təkrarlamaqdan daha asandır) Nümunələr də alqoritmlərə bənzəyir. Ancaq onların bir fərqi var. Alqoritm zəruri hərəkətləri təsvir edən xüsusi addımlardan ibarətdir. Nümunələr yalnız yanaşmanı təsvir edir, lakin icra addımlarını təsvir etmir. Nümunələr fərqlidir, çünki... müxtəlif problemləri həll edin. Tipik olaraq, aşağıdakı kateqoriyalar fərqlənir:
  • Generativ

    Bu nümunələr obyektin yaradılmasını çevik etmək problemini həll edir

  • Struktur

    Bu nümunələr obyektlər arasında əlaqələrin effektiv qurulması problemini həll edir

  • Davranış

    Bu nümunələr obyektlər arasında effektiv qarşılıqlı əlaqə problemini həll edir

Nümunələri nəzərdən keçirmək üçün repl.it onlayn kod tərtibçisindən istifadə etməyi təklif edirəm.
Java-da Dizayn Nümunələri - 2

Yaradıcı nümunələr

Obyektlərin həyat dövrünün başlanğıcından - obyektlərin yaradılması ilə başlayaq. Generativ şablonlar obyektləri daha rahat yaratmağa kömək edir və bu prosesdə çeviklik təmin edir. Ən məşhurlarından biri " İnşaatçı " dır. Bu nümunə addım-addım mürəkkəb obyektlər yaratmağa imkan verir. Java-da ən məşhur nümunə StringBuilder:
class Main {
  public static void main(String[] args) {
    StringBuilder builder = new StringBuilder();
    builder.append("Hello");
    builder.append(',');
    builder.append("World!");
    System.out.println(builder.toString());
  }
}
Obyekt yaratmaq üçün başqa bir məşhur yanaşma yaradılışı ayrıca bir üsula köçürməkdir. Bu üsul, sanki, obyekt fabrikinə çevrilir. Buna görə nümunə " Fabrik üsulu" adlanır. Məsələn, Java-da onun təsirini sinifdə görmək olar java.util.Calendar. Sinfin özü Calendarmücərrəddir və onu yaratmaq üçün metoddan istifadə olunur getInstance:
import java.util.*;
class Main {
  public static void main(String[] args) {
    Calendar calendar = Calendar.getInstance();
    System.out.println(calendar.getTime());
    System.out.println(calendar.getClass().getCanonicalName());
  }
}
Bu, çox vaxt obyektin yaradılmasının arxasında duran məntiqin mürəkkəb ola biləcəyi ilə bağlıdır. Məsələn, yuxarıdakı halda biz əsas sinfə daxil oluruq Calendarvə sinif yaradılır GregorianCalendar. Konstruktora baxsaq, şəraitdən asılı olaraq müxtəlif tətbiqlərin yaradıldığını görə bilərik Calendar. Ancaq bəzən bir zavod üsulu kifayət deyil. Bəzən müxtəlif obyektlər yaratmaq lazımdır ki, onlar bir-birinə uyğun olsun. Bu işdə bizə başqa bir şablon kömək edəcək - “ Abstrakt fabrik ”. Sonra bir yerdə müxtəlif fabriklər yaratmalıyıq. Eyni zamanda, üstünlük ondan ibarətdir ki, icra detalları bizim üçün vacib deyil, yəni. hansı konkret fabrikdən aldığımızın fərqi yoxdur. Əsas odur ki, düzgün tətbiqlər yaradır. Super misal:
Java-da Dizayn Nümunələri - 3
Yəni, mühitdən (əməliyyat sistemindən) asılı olaraq, uyğun elementlər yaradacaq müəyyən bir zavod alacağıq. Başqası vasitəsilə yaratma yanaşmasına alternativ olaraq " Prototip " nümunəsindən istifadə edə bilərik. Onun mahiyyəti sadədir - yeni obyektlər artıq mövcud olan obyektlərin təsvirində və bənzərində yaradılır, yəni. prototiplərinə görə. Java-da hər kəs bu nümunə ilə qarşılaşdı - bu interfeysdən istifadədir java.lang.Cloneable:
class Main {
  public static void main(String[] args) {
    class CloneObject implements Cloneable {
      @Override
      protected Object clone() throws CloneNotSupportedException {
        return new CloneObject();
      }
    }
    CloneObject obj = new CloneObject();
    try {
      CloneObject pattern = (CloneObject) obj.clone();
    } catch (CloneNotSupportedException e) {
      //Do something
    }
  }
}
Gördüyünüz kimi, zəng edənin necə olduğunu bilmir clone. Yəni prototip əsasında obyekt yaratmaq obyektin özünün məsuliyyətidir. Bu faydalıdır, çünki istifadəçini şablon obyektinin həyata keçirilməsinə bağlamır. Yaxşı, bu siyahıda ən sonuncusu "Singleton" nümunəsidir. Onun məqsədi sadədir - bütün tətbiq üçün obyektin bir nümunəsini təmin etmək. Bu nümunə maraqlıdır, çünki tez-tez çox iş parçacığı problemlərini göstərir. Daha dərindən baxmaq üçün bu məqalələrə baxın:
Java-da Dizayn Nümunələri - 4

Struktur nümunələri

Obyektlərin yaradılması ilə daha aydın oldu. İndi struktur nümunələrinə baxmaq vaxtıdır. Onların məqsədi asan dəstəklənən sinif iyerarxiyalarını və onların münasibətlərini qurmaqdır. İlk və məşhur nümunələrdən biri “ Müavin ”dir (Proxy). Proksi real obyektlə eyni interfeysə malikdir, ona görə də müştərinin proxy vasitəsilə və ya birbaşa işləməsinin heç bir fərqi yoxdur. Ən sadə nümunə java.lang.reflect.Proxy -dir :
import java.util.*;
import java.lang.reflect.*;
class Main {
  public static void main(String[] arguments) {
    final Map<String, String> original = new HashMap<>();
    InvocationHandler proxy = (obj, method, args) -> {
      System.out.println("Invoked: " + method.getName());
      return method.invoke(original, args);
    };
    Map<String, String> proxyInstance = (Map) Proxy.newProxyInstance(
        original.getClass().getClassLoader(),
        original.getClass().getInterfaces(),
        proxy);
    proxyInstance.put("key", "value");
    System.out.println(proxyInstance.get("key"));
  }
}
HashMapGördüyünüz kimi, nümunədə orijinal var - interfeysi həyata keçirən budur Map. Biz daha sonra zəng zamanı öz məntiqimizi əlavə edərək və metodlarını HashMapçağıran müştəri hissəsi üçün orijinalı əvəz edən proxy yaradırıq . Gördüyümüz kimi, nümunədə qarşılıqlı əlaqə interfeyslər vasitəsilə baş verir. Ancaq bəzən əvəzedici kifayət etmir. Və sonra " Dekorator " naxışından istifadə edilə bilər. Dekoratora sarğı və ya sarğı da deyilir. Proksi və dekorator çox oxşardır, lakin nümunəyə baxsanız, fərqi görəcəksiniz: putget
import java.util.*;
class Main {
  public static void main(String[] arguments) {
    List<String> list = new ArrayList<>();
    List<String> decorated = Collections.checkedList(list, String.class);
    decorated.add("2");
    list.add("3");
    System.out.println(decorated);
  }
}
Proksidən fərqli olaraq, dekorator giriş kimi ötürülən bir şeyin ətrafına sarılır. Proksi həm proksiləşdirilməli olanı qəbul edə, həm də proksiləşdirilmiş obyektin ömrünü idarə edə bilər (məsələn, etibarlı obyekt yarada). Başqa bir maraqlı nümunə var - " Adapter ". O, dekoratora bənzəyir - dekorator bir obyekti giriş kimi götürür və bu obyektin üzərinə sarğı qaytarır. Fərq ondadır ki, məqsəd funksionallığı dəyişmək deyil, bir interfeysi digərinə uyğunlaşdırmaqdır. Java-da bunun çox aydın nümunəsi var:
import java.util.*;
class Main {
  public static void main(String[] arguments) {
    String[] array = {"One", "Two", "Three"};
    List<String> strings = Arrays.asList(array);
    strings.set(0, "1");
    System.out.println(Arrays.toString(array));
  }
}
Girişdə bir massivimiz var. Sonra, massivi interfeysə gətirən bir adapter yaradırıq List. Onunla işləyərkən biz əslində massivlə işləyirik. Buna görə elementlərin əlavə edilməsi işləməyəcək, çünki... Orijinal massiv dəyişdirilə bilməz. Və bu vəziyyətdə əldə edəcəyik UnsupportedOperationException. Sinif strukturunun inkişafı üçün növbəti maraqlı yanaşma Kompozit modeldir . Maraqlıdır ki, bir interfeysdən istifadə edən müəyyən elementlər dəsti müəyyən ağaca bənzər iyerarxiyada yerləşdirilir. Ana elementdə metodu çağırmaqla biz bütün zəruri uşaq elementlərdə bu metoda zəng alırıq. Bu nümunənin əsas nümunəsi UI-dir (istər java.awt, istərsə də JSF):
import java.awt.*;
class Main {
  public static void main(String[] arguments) {
    Container container = new Container();
    Component component = new java.awt.Component(){};
    System.out.println(component.getComponentOrientation().isLeftToRight());
    container.add(component);
    container.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
    System.out.println(component.getComponentOrientation().isLeftToRight());
  }
}
Gördüyümüz kimi, konteynerə bir komponent əlavə etdik. Və sonra konteynerdən komponentlərin yeni istiqamətini tətbiq etməyi xahiş etdik. Və konteyner, hansı komponentlərdən ibarət olduğunu bilərək, bu əmrin icrasını bütün uşaq komponentlərə həvalə etdi. Digər maraqlı naxış “ Körpü ” naxışıdır. Bu, iki fərqli sinif iyerarxiyası arasında əlaqə və ya körpünü təsvir etdiyi üçün belə adlanır. Bu iyerarxiyalardan biri abstraksiya, digəri isə həyata keçirmə hesab olunur. Bu vurğulanır, çünki abstraksiya özü hərəkətləri yerinə yetirmir, lakin bu icranı həyata keçirməyə həvalə edir. Bu model tez-tez "nəzarət" sinifləri və bir neçə növ "platforma" sinifləri (məsələn, Windows, Linux və s.) olduqda istifadə olunur. Bu yanaşma ilə bu iyerarxiyalardan biri (abstraksiya) başqa bir iyerarxiyanın (tətbiq edilməsi) obyektlərinə istinad alacaq və əsas işi onlara həvalə edəcəkdir. Bütün tətbiqlər ümumi interfeysə əməl edəcəyi üçün, onlar abstraksiya daxilində dəyişdirilə bilər. Java-da bunun bariz nümunəsi java.awt:
Java-da Dizayn Nümunələri - 5
Əlavə məlumat üçün " Java AWT-də nümunələr " məqaləsinə baxın . Struktur naxışlar arasında “ Fasad ” naxışını da qeyd etmək istərdim . Onun mahiyyəti rahat və qısa interfeysin arxasında bu API arxasında kitabxanaların/çərçivələrin istifadəsinin mürəkkəbliyini gizlətməkdir. Məsələn, nümunə olaraq JPA-dan JSF və ya EntityManager-dən istifadə edə bilərsiniz. " Uçuş çəkisi " adlı başqa bir model də var . Onun mahiyyəti ondan ibarətdir ki, əgər müxtəlif obyektlər eyni vəziyyətə malikdirsə, o zaman onu ümumiləşdirmək və hər bir obyektdə deyil, bir yerdə saxlamaq olar. Və sonra hər bir obyekt ümumi hissəyə istinad edə biləcək ki, bu da saxlama üçün yaddaş xərclərini azaldacaq. Bu model tez-tez əvvəlcədən keşləşdirməni və ya obyektlərin hovuzunu saxlamağı əhatə edir. Maraqlıdır ki, biz də bu nümunəni əvvəldən bilirik:
Java-da Dizayn Nümunələri - 6
Eyni bənzətmə ilə, bir simli hovuzu buraya daxil etmək olar. Bu mövzuda məqaləni oxuya bilərsiniz: " Flyweight Design Pattern ".
Java-da Dizayn Nümunələri - 7

Davranış nümunələri

Beləliklə, biz obyektlərin necə yaradıla biləcəyini və siniflər arasında əlaqələrin necə təşkil oluna biləcəyini anladıq. Qalan ən maraqlı şey, obyektlərin davranışını dəyişdirməkdə çevikliyi təmin etməkdir. Davranış nümunələri bu işdə bizə kömək edəcəkdir. Ən çox xatırlanan nümunələrdən biri “ Strategiya ” nümunəsidir. " Əvvəlcə baş. Dizayn nümunələri " kitabındakı naxışların öyrənilməsi buradan başlayır. “Strategiya” naxışından istifadə edərək, obyektin daxilində hərəkəti necə yerinə yetirəcəyimizi saxlaya bilərik, yəni. daxilindəki obyekt kodun icrası zamanı dəyişdirilə bilən strategiyanı saxlayır. Bu, müqayisəedicidən istifadə edərkən tez-tez istifadə etdiyimiz nümunədir:
import java.util.*;
class Main {
  public static void main(String[] args) {
    List<String> data = Arrays.asList("Moscow", "Paris", "NYC");
    Comparator<String> comparator = Comparator.comparingInt(String::length);
    Set dataSet = new TreeSet(comparator);
    dataSet.addAll(data);
    System.out.println("Dataset : " + dataSet);
  }
}
Bizdən əvvəl - TreeSet. TreeSetElementlərin sırasını qorumaq davranışına malikdir , yəni. onları çeşidləyir (bir SortedSet olduğundan). Bu davranışın JavaDoc-da gördüyümüz standart strategiyası var: "təbii sıralama" ilə çeşidləmə (sətirlər üçün bu, leksikoqrafik sıradır). Bu, parametrsiz konstruktordan istifadə etsəniz baş verir. Amma strategiyanı dəyişmək istəsək, keçə bilərik Comparator. Bu misalda biz setimizi kimi yarada bilərik new TreeSet(comparator)və sonra elementlərin saxlanma qaydası (saxlama strategiyası) müqayisəedicidə göstərilənə dəyişəcək. Maraqlıdır ki, " Dövlət " adlı demək olar ki, eyni model var . “Dövlət” nümunəsi deyir ki, əgər əsas obyektdə bu obyektin vəziyyətindən asılı olan bəzi davranışlarımız varsa, o zaman dövlətin özünü obyekt kimi təsvir edə və dövlət obyektini dəyişə bilərik. Və əsas obyektdən çağırışları dövlətə həvalə edin. Java dilinin əsaslarını öyrənməkdən bizə məlum olan başqa bir nümunə “ Əmr ” nümunəsidir. Bu dizayn nümunəsi müxtəlif əmrlərin müxtəlif siniflər kimi təmsil oluna biləcəyini göstərir. Bu model Strategiya nümunəsinə çox bənzəyir. Lakin Strategiya nümunəsində biz konkret fəaliyyətin necə yerinə yetiriləcəyini yenidən müəyyənləşdirirdik (məsələn, -də çeşidləmə TreeSet). "Əmr" nümunəsində biz hansı hərəkətin yerinə yetiriləcəyini yenidən müəyyənləşdiririk. Nümunə əmri hər gün mövzulardan istifadə edərkən bizimlədir:
import java.util.*;
class Main {
  public static void main(String[] args) {
    Runnable command = () -> {
      System.out.println("Command action");
    };
    Thread th = new Thread(command);
    th.start();
  }
}
Gördüyünüz kimi, komanda yeni başlıqda yerinə yetiriləcək bir hərəkət və ya əmri müəyyən edir. “ Məsuliyyət zənciri” nümunəsini də nəzərdən keçirməyə dəyər . Bu model də çox sadədir. Bu nümunə deyir ki, bir şeyin emal edilməsi lazımdırsa, onda bir zəncirdə işləyiciləri toplaya bilərsiniz. Məsələn, bu model tez-tez veb serverlərdə istifadə olunur. Girişdə serverin istifadəçidən müəyyən sorğusu var. Bu sorğu daha sonra emal zəncirindən keçir. Bu işləyicilər zəncirinə filtrlər (məsələn, IP ünvanlarının qara siyahısından gələn sorğuları qəbul etməyin), autentifikasiya işləyiciləri (yalnız səlahiyyətli istifadəçilərə icazə verilir), sorğu başlığının işləyicisi, keş işləyicisi və s. daxildir. Ancaq Java-da daha sadə və daha başa düşülən bir nümunə var java.util.logging:
import java.util.logging.*;
class Main {
  public static void main(String[] args) {
    Logger logger = Logger.getLogger(Main.class.getName());
    ConsoleHandler consoleHandler = new ConsoleHandler(){
		@Override
            public void publish(LogRecord record) {
                System.out.println("LogRecord обработан");
            }
        };
    logger.addHandler(consoleHandler);
    logger.info("test");
  }
}
Gördüyünüz kimi, İşləyicilər logger işləyiciləri siyahısına əlavə edilmişdir. Qeydiyyatçı emal üçün bir mesaj aldıqda, hər bir belə mesaj həmin logger üçün işləyicilər zəncirindən (-dən logger.getHandlers) keçir. Hər gün gördüyümüz başqa bir nümunə “ İterator ”dur. Onun mahiyyəti obyektlər toplusunu (yəni, verilənlər strukturunu təmsil edən sinif. Məsələn, List) və bu kolleksiyanın keçidini ayırmaqdan ibarətdir.
import java.util.*;
class Main {
  public static void main(String[] args) {
    List<String> data = Arrays.asList("Moscow", "Paris", "NYC");
    Iterator<String> iterator = data.iterator();
    while (iterator.hasNext()) {
      System.out.println(iterator.next());
    }
  }
}
Gördüyünüz kimi, iterator kolleksiyanın bir hissəsi deyil, kolleksiyadan keçən ayrıca siniflə təmsil olunur. İteratorun istifadəçisi onun hansı kolleksiya üzərində təkrarlandığını belə bilməyə bilər, yəni. hansı kolleksiyanı ziyarət edir? “ Ziyarətçi ” nümunəsini nəzərdən keçirməyə dəyər . Ziyarətçi nümunəsi iterator modelinə çox bənzəyir. Bu nümunə obyektlərin strukturundan yan keçməyə və bu obyektlər üzərində hərəkətlər etməyə kömək edir. Onlar konsepsiya baxımından daha çox fərqlənirlər. İterator kolleksiyadan keçir ki, iteratordan istifadə edən müştəri kolleksiyanın içərisində nə olduğuna əhəmiyyət verməsin, yalnız ardıcıllıqdakı elementlər vacibdir. Ziyarətçi o deməkdir ki, ziyarət etdiyimiz obyektlərin müəyyən bir iyerarxiyası və ya strukturu var. Məsələn, biz ayrı-ayrı kataloq emalı və ayrıca fayl emalından istifadə edə bilərik. Java-da bu nümunənin qutudan kənar bir tətbiqi var java.nio.file.FileVisitor:
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.*;
class Main {
  public static void main(String[] args) {
    SimpleFileVisitor visitor = new SimpleFileVisitor() {
      @Override
      public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException {
        System.out.println("File:" + file.toString());
        return FileVisitResult.CONTINUE;
      }
    };
    Path pathSource = Paths.get(System.getProperty("java.io.tmpdir"));
    try {
      Files.walkFileTree(pathSource, visitor);
    } catch (AccessDeniedException e) {
      // skip
    } catch (IOException e) {
      // Do something
    }
  }
}
Bəzən bəzi obyektlərin digər obyektlərdəki dəyişikliklərə reaksiya verməsi tələb olunur və sonra "Müşahidəçi" nümunəsi bizə kömək edəcəkdir . Ən əlverişli yol, bəzi obyektlərə digər obyektlərdə baş verən hadisələri izləmək və onlara cavab vermək imkanı verən abunə mexanizmini təmin etməkdir. Bu nümunə tez-tez müxtəlif hadisələrə reaksiya verən müxtəlif Dinləyicilərdə və Müşahidəçilərdə istifadə olunur. Sadə bir nümunə olaraq, JDK-nın ilk versiyasından bu nümunənin həyata keçirilməsini xatırlaya bilərik:
import java.util.*;
class Main {
  public static void main(String[] args) {
    Observer observer = (obj, arg) -> {
      System.out.println("Arg: " + arg);
    };
    Observable target = new Observable(){
      @Override
      public void notifyObservers(Object arg) {
        setChanged();
        super.notifyObservers(arg);
      }
    };
    target.addObserver(observer);
    target.notifyObservers("Hello, World!");
  }
}
Başqa bir faydalı davranış nümunəsi var - “ Vasitəçi ”. Bu faydalıdır, çünki mürəkkəb sistemlərdə müxtəlif obyektlər arasındakı əlaqəni aradan qaldırmağa və obyektlər arasında bütün qarşılıqlı əlaqəni vasitəçi olan bəzi obyektə həvalə etməyə kömək edir. Bu nümunənin ən təəccüblü tətbiqlərindən biri bu nümunədən istifadə edən Spring MVC-dir. Bu barədə daha ətraflı burada oxuya bilərsiniz: " Bahar: Vasitəçi Pattern ". Çox vaxt eyni şeyi misallarda görə bilərsiniz java.util.Timer:
import java.util.*;
class Main {
  public static void main(String[] args) {
    Timer mediator = new Timer("Mediator");
    TimerTask command = new TimerTask() {
      @Override
      public void run() {
        System.out.println("Command pattern");
        mediator.cancel();
      }
    };
    mediator.schedule(command, 1000);
  }
}
Nümunə daha çox əmr nümunəsinə bənzəyir. Və "Vasitəçi" nümunəsinin mahiyyəti Timer'a'nın həyata keçirilməsində gizlidir. Taymerin içərisində tapşırıq növbəsi TaskQueue, iplik var TimerThread. Biz, bu sinfin müştəriləri olaraq, onlarla əlaqə saxlamırıq, lakin Timeronun metodlarına çağırışımıza cavab olaraq, vasitəçi olduğu digər obyektlərin metodlarına daxil olan obyektlə qarşılıqlı əlaqədə oluruq. Xarici olaraq, "Fasad" a çox oxşar görünə bilər. Amma fərq ondadır ki, Fasad istifadə edildikdə komponentlər fasadın mövcud olduğunu bilmir və bir-biri ilə danışır. Və "Vasitəçi" istifadə edildikdə, komponentlər vasitəçini tanıyır və istifadə edir, lakin bir-biri ilə birbaşa əlaqə saxlamır. “ Şablon metodu ” naxışını nəzərdən keçirməyə dəyər.Nümunə adından aydın görünür. Nəticə ondan ibarətdir ki, kod elə yazılıb ki, kodun istifadəçiləri (inkişafçılar) bəzi alqoritm şablonu ilə təmin olunur, onun addımlarının yenidən müəyyənləşdirilməsinə icazə verilir. Bu, kod istifadəçilərinə bütün alqoritmi yazmağa deyil, yalnız bu alqoritmin bu və ya digər addımını necə düzgün yerinə yetirmək barədə düşünməyə imkan verir. Məsələn, Java-da AbstractListiteratorun davranışını müəyyən edən mücərrəd sinif var List. Bununla belə, iterator özü yarpaq üsullarından istifadə edir, məsələn: get, set, remove. Bu üsulların davranışı nəslin inkişaf etdiricisi tərəfindən müəyyən edilir AbstractList. Beləliklə, iterator AbstractList- vərəq üzərində təkrarlama alqoritmi üçün şablondur. Xüsusi tətbiqlərin tərtibatçıları isə AbstractListkonkret addımların davranışını müəyyən etməklə bu iterasiyanın davranışını dəyişirlər. Təhlil etdiyimiz nümunələrin sonuncusu “ Snapshot ” (Momento) nümunəsidir. Onun mahiyyəti obyektin müəyyən vəziyyətini bu vəziyyəti bərpa etmək qabiliyyəti ilə qorumaqdır. JDK-dan ən tanınan nümunə obyektin seriallaşdırılmasıdır, yəni. java.io.Serializable. Bir misala baxaq:
import java.io.*;
import java.util.*;
class Main {
  public static void main(String[] args) throws IOException {
    ArrayList<String> list = new ArrayList<>();
    list.add("test");
    // Save State
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    try (ObjectOutputStream out = new ObjectOutputStream(stream)) {
      out.writeObject(list);
    }
    // Load state
    byte[] bytes = stream.toByteArray();
    InputStream inputStream = new ByteArrayInputStream(bytes);
    try (ObjectInputStream in = new ObjectInputStream(inputStream)) {
      List<String> listNew = (List<String>) in.readObject();
      System.out.println(listNew.get(0));
    } catch (ClassNotFoundException e) {
      // Do something. Can't find class fpr saved state
    }
  }
}
Java-da Dizayn Nümunələri - 8

Nəticə

Nəzərdən gördüyümüz kimi, çox sayda nümunə var. Onların hər biri öz problemini həll edir. Və bu nümunələr haqqında bilik sizə sisteminizi çevik, davamlı və dəyişikliyə davamlı olması üçün necə yazacağınızı vaxtında başa düşməyə kömək edə bilər. Və nəhayət, daha dərin dalış üçün bəzi bağlantılar: #Viaçeslav
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION