JavaRush /Java блогу /Random-KY /Java тилиндеги дизайн үлгүлөрү
Viacheslav
Деңгээл

Java тилиндеги дизайн үлгүлөрү

Группада жарыяланган
Үлгүлөр же дизайн үлгүлөрү иштеп чыгуучунун жумушунун көп учурда көз жаздымда калган бөлүгү болуп саналат, бул codeду сактоону жана жаңы талаптарга көнүүнү кыйындатат. Мен сизге анын эмне экенин жана JDKде кантип колдонуларын карап көрүүнү сунуштайм. Албетте, тигил же бул формадагы бардык негизги үлгүлөр биздин айланабызда көптөн бери болуп келген. Келгиле, аларды бул кароодо карап көрөлү.
Java тorнде дизайн үлгүлөрү - 1
Мазмуну:

Шаблондор

Вакансиялардагы эң кеңири таралган талаптардын бири – “Үлгүлөрдү билүү”. Биринчиден, жөнөкөй суроого жооп берүү керек - "Дизайн үлгүсү деген эмне?" Pattern англис тorнен "шаблон" деп которулган. Башкача айтканда, бул биз бир нерсе жасай турган белгилүү бир үлгү. Программалоодо да ушундай. Жалпы көйгөйлөрдү чечүү үчүн кээ бир калыптанган мыкты тажрыйбалар жана ыкмалар бар. Ар бир программист – архитектор. Сиз бир нече класстарды же бирөөнү гана түзсөңүз дагы, бул code өзгөрүп жаткан талаптарда канча убакыт жашай ала тургандыгы, аны башкалар колдонуу канчалык ыңгайлуу экендиги сизге көз каранды. Бул жерде калыптарды билүү жардам берет, анткени... Бул сизге codeду кайра жазбастан кантип мыкты жазууну тез түшүнүүгө мүмкүндүк берет. Белгилүү болгондой, программисттер жалкоо адамдар жана аны бир нече жолу кайталаганга караганда, дароо жакшы жазуу оңой) Үлгүлөр да алгоритмдерге окшош болушу мүмкүн. Бирок алардын айырмасы бар. Алгоритм зарыл болгон аракеттерди сүрөттөгөн конкреттүү кадамдардан турат. Үлгүлөр гана ыкманы сүрөттөйт, бирок ишке ашыруу кадамдарын сүрөттөбөйт. Үлгүлөр ар түрдүү, анткени... ар кандай маселелерди чечүү. Эреже катары, төмөнкү категориялар бөлүнөт:
  • Генеративдик

    Бул үлгүлөр an objectти түзүүнү ийкемдүү кылуу маселесин чечет

  • Структуралык

    Бул моделдер an objectилердин ортосундагы байланыштарды натыйжалуу куруу маселесин чечет

  • Жүрүм-турум

    Бул моделдер an objectилердин ортосундагы эффективдүү өз ара аракеттенүү маселесин чечет

Мисалдарды карап чыгуу үчүн мен repl.it онлайн code компиляторун колдонууну сунуштайм.
Java тorнде дизайн үлгүлөрү - 2

Жаратуу моделдери

Объекттердин жашоо циклинин башталышынан баштайлы - an objectтерди түзүү менен. Генеративдик шаблондор an objectтерди ыңгайлуураак түзүүгө жардам берет жана бул процессте ийкемдүүлүктү камсыз кылат. Алардын ичинен эң белгилүүсү " Строитель ". Бул үлгү татаал an objectилерди этап-этабы менен түзүүгө мүмкүндүк берет. Javaда эң белгилүү мисал 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());
  }
}
Объектти түзүүнүн дагы бир белгилүү ыкмасы - бул түзүүнү өзүнчө ыкмага жылдыруу. Бул ыкма an objectorк заводго айланат. Ошол себептен үлгү « Заводдук ыкма» деп аталат. Мисалы, Java тorнде анын эффектин класста көрүүгө болот java.util.Calendar. Класстын өзү Calendarабстракттуу жана аны түзүү үчүн төмөнкү ыкма колдонулат 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());
  }
}
Бул көбүнчө an objectти түзүүнүн логикасы татаал болушу мүмкүн. Мисалы, жогорудагы учурда биз базалык класска киребиз Calendarжана класс түзүлөт GregorianCalendar. Эгер конструкторду карасак, шарттарга жараша ар кандай ишке ашыруулар түзүлгөнүн көрөбүз Calendar. Бирок кээде заводдун бир ыкмасы жетишсиз. Кээде алар бири-бирине дал келиши үчүн ар кандай an objectтерди түзүү керек. Бул жагынан бизге дагы бир шаблон жардам берет - " Абстракттуу фабрика ". Анан бир жерден ар кандай заводдорду түзүшүбүз керек. Ошол эле учурда, артыкчылыгы - ишке ашыруунун деталдары биз үчүн маанилүү эмес, б.а. конкреттүү кайсы завод алганыбыз маанилүү эмес. Эң негизгиси, ал туура ишке ашырууларды түзөт. Супер мисал:
Java тorнде дизайн үлгүлөрү - 3
Башкача айтканда, айлана-чөйрөгө (иштөө системасы) жараша, биз шайкеш элементтерди түзө турган белгилүү бир заводду алабыз. Башка бирөө аркылуу түзүү ыкмасына альтернатива катары биз " Прототип " үлгүсүн колдоно алабыз. Анын маңызы жөнөкөй - жаңы an objectтер мурунтан эле бар an objectтердин элеси жана окшоштугунда түзүлөт, б.а. алардын прототиби боюнча. Javaда бардыгы бул үлгүгө туш болушкан - бул интерфейсти колдонуу 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
    }
  }
}
Көрүнүп тургандай, чалуучу кантип clone. Башкача айтканда, прототиптин негизинде an objectти түзүү an objectтин өзүнө жүктөлөт. Бул пайдалуу, анткени ал колдонуучуну шаблон an objectин ишке ашырууга байлаbyte. Ооба, бул тизмедеги эң акыркысы "Singleton" үлгүсү. Анын максаты жөнөкөй - бүтүндөй колдонмо үчүн an objectтин бир нускасын берүү. Бул үлгү кызыктуу, анткени ал көп агымдагы көйгөйлөрдү көп көрсөтөт. Көбүрөөк маалымат алуу үчүн, бул макалаларды караңыз:
Java тorнде дизайн үлгүлөрү - 4

Структуралык моделдер

Объекттердин жаралышы менен айкыныраак болуп калды. Азыр структуралык үлгүлөрдү карап чыгууга убакыт келди. Алардын максаты - колдоо үчүн жеңил класс иерархиясын жана алардын мамилелерин куруу. Биринчи жана белгилүү үлгүлөрдүн бири " Депутат " (прокси). Прокси чыныгы an object менен бирдей интерфейске ээ, андыктан кардардын прокси аркылуу же түз иштеши эч кандай айырмасы жок. Эң жөнөкөй мисал java.lang.reflect.Proxy :
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"));
  }
}
Көрүнүп тургандай, мисалда бизде оригиналдуу - бул HashMapинтерфейсти ишке ашыруучу Map. Андан кийин биз чалуу учурунда өзүбүздүн логиканы кошуп, жана ыкмаларын HashMapчакырган кардар бөлүгү үчүн түпнускасын алмаштырган прокси түзөбүз . Көрүнүп тургандай, үлгүдөгү өз ара аракеттенүү интерфейстер аркылуу ишке ашат. Бирок кээде алмаштыруучу жетиштүү эмес. Анан " Декоратор " үлгүсүн колдонсо болот. Декораторду орогуч же орогуч деп да аташат. Прокси жана декоратор абдан окшош, бирок мисалды карасаңыз, айырманы көрөсүз: 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);
  }
}
Проксиден айырмаланып, жасалгалоочу киргизүү катары берилген нерсенин айланасына ороп алат. Прокси проксиден өтүшү керек болгон нерсени кабыл ала алат, ошондой эле проксиленген an objectтин иштөө мөөнөтүн башкара алат (мисалы, прокси an objectти түзө алат). Дагы бир кызыктуу үлгү бар - " Адаптер ". Бул жасалгалоочуга окшош - жасалгалоочу бир an objectти киргизүү катары кабыл алып, бул an objectтин үстүнө орогучту кайтарат. Айырмачылыгы – бул функцияны өзгөртүү эмес, бир интерфейсти экинчисине ыңгайлаштыруу. Java мунун абдан ачык мисалы бар:
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));
  }
}
Киргизүүдө бизде массив бар. Андан кийин массивди интерфейске алып келген адаптерди түзөбүз List. Аны менен иштөөдө биз чындыгында массив менен иштеп жатабыз. Демек, элементтерди кошуу иштебейт, анткени... Түпнуска массивди өзгөртүү мүмкүн эмес. Жана бул учурда биз алабыз UnsupportedOperationException. Класстык түзүлүштү өнүктүрүүнүн кийинки кызыктуу ыкмасы - Композиттик үлгү . Кызыктуусу, бир интерфейсти колдонгон элементтердин белгилүү бир топтому белгилүү бир дарак сыяктуу иерархияда жайгаштырылат. Ата-энелик элементте методду чакыруу менен, биз бардык зарыл болгон кошумча элементтерде бул ыкмага чакыруу алабыз. Бул үлгүнүн негизги мисалы UI (бул java.awt же 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());
  }
}
Көрүнүп тургандай, биз контейнерге бир компонентти коштук. Анан биз контейнерден компоненттердин жаңы багытын колдонууну сурандык. Ал эми контейнер, анын кандай компоненттерден тураарын бorп, бул буйруктун аткарылышын бардык бала компоненттерге тапшырган. Дагы бир кызыктуу үлгү - " Көпүрө " үлгүсү. Бул эки түрдүү класс иерархиясынын ортосундагы байланышты же көпүрөнү сүрөттөгөндүктөн деп аталат. Бул иерархиялардын бири абстракция, экинчиси ишке ашыруу болуп эсептелет. Бул баса белгиленген, анткени абстракция өзү иш-аракеттерди аткарbyte, бирок бул аткарууну ишке ашырууга өткөрүп берет. Бул үлгү көбүнчө "контролдук" класстар жана "платформа" класстарынын бир нече түрлөрү (мисалы, Windows, Linux ж.б.) болгондо колдонулат. Мындай ыкма менен бул иерархиялардын бири (абстракция) башка иерархиянын (ишке ашыруунун) an objectтерине шилтеме алат жана аларга негизги ишти өткөрүп берет. Бардык ишке ашыруулар жалпы интерфейске ылайык болгондуктан, аларды абстракциянын ичинде алмаштырса болот. Javaда мунун ачык мисалы java.awt:
Java тorнде дизайн үлгүлөрү - 5
Көбүрөөк маалымат алуу үчүн, макаланы карагыла " Java AWT үлгүлөрү ". Структуралык үлгүлөрдүн ичинен мен “ Фасад ” үлгүсүн да белгилегим келет . Анын маңызы китепканаларды/алHowтарды колдонуунун татаалдыгын бул API артына ыңгайлуу жана кыска интерфейстин артына жашыруу болуп саналат. Мисалы, сиз мисал катары JPAдан JSF же EntityManager колдоно аласыз. " Чымын салмак " деп аталган дагы бир үлгү дагы бар . Анын маңызы, эгерде ар кандай an objectтер бирдей абалга ээ болсо, анда ал жалпыланып, ар бир an objectте эмес, бир жерде сакталышы мүмкүн. Анан ар бир an object жалпы бөлүккө шилтеме жасай алат, бул сактоо үчүн эстутум чыгымдарын азайтат. Бул үлгү көбүнчө an objectтердин бассейнин алдын ала кэштөө же сактоону камтыйт. Кызыктуусу, биз бул үлгүнү эң башынан эле билебиз:
Java тorнде дизайн үлгүлөрү - 6
Ошол эле окшоштук боюнча, бул жерге саптардын бассейнин кошууга болот. Бул тема боюнча макаланы окуй аласыз: " Flyweight Design Pattern ".
Java тorнде дизайн үлгүлөрү - 7

Жүрүм-турум үлгүлөрү

Ошентип, биз an objectтерди кантип түзүүгө болорун жана класстар ортосундагы байланыштарды кантип уюштурууга болорун түшүндүк. Калган эң кызыктуу нерсе - an objectтердин жүрүм-турумун өзгөртүүдө ийкемдүүлүктү камсыз кылуу. Ал эми жүрүм-турум үлгүлөрү бул жагынан бизге жардам берет. Эң көп айтылган үлгүлөрдүн бири - " Стратегия " үлгүсү. " Биринчи баш. Дизайн үлгүлөрү " китебиндеги оймо-чиймелерди изилдөө ушул жерден башталат. "Стратегия" үлгүсүн колдонуу менен биз an objectтин ичинде биз кандай аракет кылаарыбызды сактай алабыз, б.а. ичиндеги an object codeду аткаруу учурунда өзгөртө турган стратегияны сактайт. Бул салыштыргычты колдонууда биз көп колдонгон үлгү:
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);
  }
}
Бизге чейин - TreeSet. TreeSetАл элементтердин тартибин сактоо жүрүм-турумуна ээ , б.а. аларды сорттойт (анткени ал SortedSet). Бул жүрүм-турумдун демейки стратегиясы бар, аны биз JavaDocта көрөбүз: "табигый иреттөө" боюнча сорттоо (саптар үчүн бул лексикографиялык тартип). Бул параметрсиз конструкторду колдонсоңуз болот. Бирок стратегияны өзгөрткүбүз келсе, анда биз өтө алабыз Comparator. Бул мисалда биз топтомубузду түзө алабыз new TreeSet(comparator), андан кийин элементтерди сактоо тартиби (сактоо стратегиясы) компаратордо көрсөтүлгөнгө өзгөрөт. Кызыгы, " Мамлекет " деп аталган дээрлик бирдей үлгү бар . "Мамлекет" үлгүсү, эгерде бизде бул an objectтин абалына көз каранды болгон негизги an objectте кандайдыр бир жүрүм-турум болсо, анда биз мамлекеттин өзүн an object катары сүрөттөп, абалдын an objectисин өзгөртө алабыз деп айтылат. Ал эми негизги an objectтен мамлекетке чакырууларды делегат. Java тorнин негиздерин изилдөөдө бизге белгилүү болгон дагы бир үлгү бул “ Буйрук ” үлгүсү. Бул дизайн үлгүсү ар кандай буйруктарды ар кандай класстар катары көрсөтүшү мүмкүн экенин көрсөтүп турат. Бул үлгү Стратегиянын үлгүсүнө абдан окшош. Бирок Стратегиянын үлгүсүндө биз конкреттүү иш-аракеттин кантип аткарылаарын кайра аныктап жатканбыз (мисалы, сорттоо TreeSet). "Буйрук" үлгүсүндө биз кандай иш-аракет аткарыла турганын кайрадан аныктайбыз. Үлгү буйругу күн сайын жиптерди колдонгондо биз менен болот:
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();
  }
}
Көрүнүп тургандай, команда жаңы жипте аткарыла турган иш-аракетти же буйрукту аныктайт. “ Жоопкерчorк чынжырчасы” үлгүсүн да эске алуу зарыл . Бул үлгү да абдан жөнөкөй. Бул үлгү бир нерсени иштетүү керек болсо, анда сиз чынжыр менен иштеткичтерди чогулта аласыз деп айтылат. Мисалы, бул үлгү көбүнчө веб-serverлерде колдонулат. Киргизүүдө serverде колдонуучудан кандайдыр бир өтүнүч бар. Бул сурам кайра иштетүү чынжырынан өтөт. Иштетүүчүлөрдүн бул чынжырчасы чыпкаларды камтыйт (мисалы, IP даректеринин кара тизмесинен суроо-талаптарды кабыл албаңыз), аутентификация иштеткичтери (автификацияланган колдонуучуларга гана уруксат берүү), суроо-талаптын аталышын иштеткич, кэш иштетүүчү ж.б. Бирок Javaда жөнөкөй жана түшүнүктүү бир мисал бар 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");
  }
}
Көрүнүп тургандай, Handlers журналдарды иштетүүчүлөрдүн тизмесине кошулган. logger.getHandlersКаттагыч иштетүү үчүн билдирүүнү алганда, ар бир мындай билдирүү ошол каттоочу үчүн иштетүүчүлөрдүн чынжырынан (ден) өтөт . Биз күн сайын көргөн дагы бир үлгү - " Итератор ". Анын маңызы an objectтердин коллекциясын (б.а. маалымат структурасын билдирген класс. Мисалы, List) жана бул коллекциянын өтүшүн бөлүү болуп саналат.
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());
    }
  }
}
Көрүнүп тургандай, итератор коллекциянын бир бөлүгү эмес, коллекцияны басып өткөн өзүнчө класс менен көрсөтүлөт. Итератордун колдонуучусу ал кайсы коллекцияны кайталап жатканын билбеши мүмкүн, б.а. ал кайсы коллекцияга барат? Visitor үлгүсү да карап чыгууга арзыйт . Келүүчү үлгү итератор үлгүсүнө абдан окшош. Бул үлгү an objectтердин түзүмүн айланып өтүүгө жана бул an objectтерде аракеттерди аткарууга жардам берет. Алар концепциясы боюнча бир кыйла айырмаланат. Итератор коллекцияны аралайт, ошондуктан итераторду колдонгон кардар коллекциянын ичинде эмне бар экенине маани бербейт, ырааттуулуктагы элементтер гана маанилүү. Келүүчү дегенибиз, биз барган an objectтердин белгилүү бир иерархиясы же структурасы бар экенин билдирет. Мисалы, биз өзүнчө каталог иштетүүнү жана өзүнчө файлды иштетүүнү колдоно алабыз. Java бул үлгүнү төмөнкү формада ишке ашырууга ээ 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
    }
  }
}
Кээде кээ бир an objectтердин башка an objectтердеги өзгөрүүлөргө реакциясы керек болот, андан кийин бизге "Байкоочу" үлгүсү жардам берет . Эң ыңгайлуу жолу - бул кээ бир an objectтерге башка an objectтерде болуп жаткан окуяларга мониторинг жүргүзүүгө жана аларга жооп берүүгө мүмкүндүк берген жазылуу механизмин камсыз кылуу. Бул үлгү көбүнчө ар кандай окуяларга жооп берген ар кандай угуучуларда жана байкоочуларда колдонулат. Жөнөкөй мисал катары, биз JDK биринчи versionсынан бул үлгүнүн аткарылышын эстей алабыз:
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!");
  }
}
Дагы бир пайдалуу жүрүм-турум үлгүсү бар - " Оратор ". Бул пайдалуу, анткени татаал системаларда ар кандай an objectтердин ортосундагы байланышты жоюуга жана an objectтердин ортосундагы бардык өз ара аракеттенүүнү ортомчу болгон кандайдыр бир an objectке өткөрүп берүүгө жардам берет. Бул үлгүнүн эң көрүнүктүү колдонмолорунун бири бул үлгүнү колдонгон Spring MVC. Бул тууралуу кененирээк бул жерден окуй аласыз: " Жаз: Медиатор үлгүсү ". Сиз көп учурда мисалдардан эле көрө аласыз 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);
  }
}
Мисал буйрук үлгүсүнө көбүрөөк окшош. Ал эми «Медиатор» үлгүсүнүн маңызы Timer»а ишке ашырууда катылган. Таймердин ичинде тапшырма кезеги TaskQueue, жип бар TimerThread. Биз, бул класстын кардарлары катары, алар менен өз ара аракеттенбейбиз, бирок Timerанын методдоруна биздин чакырыгыбызга жооп катары, ал ортомчу болгон башка an objectтердин ыкмаларына кире турган an object менен өз ара аракеттенебиз. Сыртынан караганда "Фасадга" абдан окшош сезorши мүмкүн. Бирок айырмасы, Фасад колдонулганда компоненттер фасаддын бар экенин бorшпейт жана бири-бири менен сүйлөшүшөт. Ал эми "Медиатор" колдонулганда, компоненттер ортомчуну бorшет жана колдонушат, бирок бири-бири менен түздөн-түз байланышпайт. Бул үчүн “ Шаблон ыкмасы ” үлгүсүн карап чыгуу зарыл.Үлгү анын атынан көрүнүп турат. Жыйынтык - codeдун колдонуучулары (иштеп чыгуучулар) кадамдарын кайра аныктоого уруксат берилген алгоритм шаблону менен камсыздалгандай кылып жазылган. Бул code колдонуучуларга бүт алгоритмди жазууга эмес, бул алгоритмдин тигил же бул кадамын кантип туура аткаруу жөнүндө гана ойлонууга мүмкүндүк берет. Мисалы, Javaда AbstractListитератордун жүрүм-турумун аныктаган абстракттуу класс бар List. Бирок, итератор өзү жалбырак ыкмаларын колдонот, мисалы: get, set, remove. Бул ыкмалардын жүрүм-туруму урпактарды иштеп чыгуучу тарабынан аныкталат AbstractList. Ошентип, итератор AbstractList- бул барактын үстүндө итерациялоо алгоритминин шаблону. Ал эми конкреттүү ишке ашырууну иштеп чыгуучулар AbstractListконкреттүү кадамдардын жүрүм-турумун аныктоо менен бул итерациянын жүрүм-турумун өзгөртүшөт. Биз талдап жаткан үлгүлөрдүн акыркысы - бул " Снапшот " (Momento) үлгүсү. Анын маңызы бул абалды калыбына келтирүү мүмкүнчүлүгү менен an objectтин белгилүү бир абалын сактап калуу болуп саналат. JDKтин эң таанымал мисалы an objectти сериалдаштыруу, б.а. java.io.Serializable. Келгиле, бир мисал карап көрөлү:
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 тorнде дизайн үлгүлөрү - 8

Корутунду

Карап чыгуудан көрүнүп тургандай, моделдердин көп түрдүүлүгү бар. Алардын ар бири өз маселесин чечет. Жана бул калыптарды билүү сиздин системаңызды ийкемдүү, туруктуу жана өзгөрүүгө туруштук бере тургандай кылып жазууну өз убагында түшүнүүгө жардам берет. Акыр-аягы, тереңирээк чөмүлүү үчүн кээ бир шилтемелер: #Вячеслав
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION