JavaRush /Java блогы /Random-KK /Java тіліндегі дизайн үлгілері
Viacheslav
Деңгей

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

Топта жарияланған
Үлгілер немесе дизайн үлгілері әзірлеуші ​​жұмысының жиі назардан тыс қалған бөлігі болып табылады, бұл codeты сақтауды және жаңа талаптарға бейімделуді қиындатады. Мен сізге оның не екенін және JDK-де қалай қолданылатынын қарауды ұсынамын. Әрине, бір немесе басқа формадағы барлық негізгі үлгілер біздің айналамызда ұзақ уақыт бойы болды. Оларды осы шолуда көрейік.
Java тіліндегі дизайн үлгілері - 1
Мазмұны:

Үлгілер

Бос орындарға қойылатын ең көп таралған талаптардың бірі - «Үлгілерді білу». Ең алдымен, қарапайым сұраққа жауап беру керек - «Дизайн үлгісі дегеніміз не?» Pattern ағылшын тілінен «үлгі» деп аударылған. Яғни, бұл біз бірдеңе жасайтын белгілі бір үлгі. Бағдарламалауда да солай. Жалпы проблемаларды шешудің кейбір бекітілген озық тәжірибелері мен тәсілдері бар. Әрбір бағдарламашы – сәулетші. Тіпті бірнеше сыныпты немесе тіпті біреуін жасаған кезде де, өзгеретін талаптарда codeтың қаншалықты ұзақ өмір сүре алатындығы, оны басқалар пайдалану қаншалықты ыңғайлы екендігі сізге байланысты. Бұл жерде үлгілерді білу көмектеседі, өйткені... Бұл codeты қайта жазусыз қалай жақсы жазу керектігін тез түсінуге мүмкіндік береді. Өздеріңіз білетіндей, бағдарламашылар жалқау адамдар және бір нәрсені бірнеше рет қайталаудан гөрі бірден жақсы жазу оңайырақ) Үлгілер де алгоритмдерге ұқсас болып көрінуі мүмкін. Бірақ олардың айырмашылығы бар. Алгоритм қажетті әрекеттерді сипаттайтын нақты қадамдардан тұрады. Үлгілер тек тәсілді сипаттайды, бірақ іске асыру қадамдарын сипаттамайды. Үлгілері әртүрлі, өйткені... әртүрлі мәселелерді шешу. Әдетте келесі категориялар бөлінеді:
  • Генеративті

    Бұл үлгілер an object құруды икемді ету мәселесін шешеді

  • Құрылымдық

    Бұл үлгілер an objectілер арасындағы байланыстарды тиімді құру мәселесін шешеді

  • Мінез-құлық

    Бұл үлгілер an objectілер арасындағы тиімді әрекеттесу мәселесін шешеді

Мысалдарды қарастыру үшін мен repl.it онлайн code құрастырушысын пайдалануды ұсынамын.
Java тіліндегі дизайн үлгілері - 2

Шығармашылық үлгілер

Объектілердің өмірлік циклінің басынан - 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());
  }
}
Объектіні құрудың тағы бір танымал тәсілі - жасауды бөлек әдіске көшіру. Бұл әдіс нысан зауытына айналады. Сондықтан үлгі « Зауыттық әдіс» деп аталады. Мысалы, Java тілінде оның әсерін сыныпта көруге болады 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. Бірақ кейде бір зауыттық әдіс жеткіліксіз. Кейде бір-біріне сәйкес келетіндей әртүрлі нысандарды жасау керек. Бұл бізге тағы бір үлгі көмектеседі - « Дерексіз фабрика ». Сосын бір жерден түрлі зауыттар құру керек. Сонымен қатар, артықшылығы - іске асыру туралы мәліметтер біз үшін маңызды емес, яғни. нақты қандай зауыт алатынымыз маңызды емес. Ең бастысы, ол дұрыс іске асыруды жасайды. Супер мысал:
Java тіліндегі дизайн үлгілері - 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інің өзіне жүктеледі. Бұл пайдалы, себебі ол пайдаланушыны үлгі нысанын жүзеге асыруға байланыстырмайды. Бұл тізімдегі ең соңғысы - «Singleton» үлгісі. Оның мақсаты қарапайым – бүкіл қолданба үшін нысанның бір данасын қамтамасыз ету. Бұл үлгі қызықты, себебі ол көп ағынды мәселелерді жиі көрсетеді. Толығырақ қарау үшін мына мақалаларды қараңыз:
Java тіліндегі дизайн үлгілері - 4

Құрылымдық үлгілер

Объектілерді құрумен ол айқынырақ болды. Енді құрылымдық үлгілерді қарастыратын уақыт. Олардың мақсаты - қолдауға оңай класс иерархияларын және олардың қарым-қатынастарын құру. Алғашқы және белгілі үлгілердің бірі – « Орынбасар » (прокси). Проксидің нақты нысан сияқты интерфейсі бар, сондықтан клиенттің прокси арқылы немесе тікелей жұмыс істеуі ешқандай айырмашылығы жоқ. Ең қарапайым мысал 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);
  }
}
Проксиден айырмашылығы, декоратор кіріс ретінде берілетін нәрсенің айналасына орап алады. Прокси прокси болуы қажет нәрсені қабылдай алады, сонымен қатар проксиденген нысанның қызмет ету мерзімін басқара алады (мысалы, прокси нысанын жасау). Тағы бір қызықты үлгі бар - « Адаптер ». Ол декораторға ұқсайды - декоратор кіріс ретінде бір нысанды алып, осы нысанның үстінен қаптаманы қайтарады. Айырмашылығы - мақсат функционалдылықты өзгерту емес, бір интерфейсті екіншісіне бейімдеу. 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());
  }
}
Көріп отырғанымыздай, біз контейнерге құрамдас қостық. Содан кейін біз контейнерден компоненттердің жаңа бағытын қолдануды сұрадық. Ал контейнер өзінің қандай компоненттерден тұратынын біле отырып, осы команданың орындалуын барлық еншілес компоненттерге берді. Тағы бір қызықты үлгі – « Көпір » үлгісі. Бұл екі түрлі класс иерархиясы арасындағы байланысты немесе көпірді сипаттайтындықтан осылай аталады. Бұл иерархияның бірі абстракция, ал екіншісі іске асыру болып саналады. Бұл бөлектелген, себебі абстракцияның өзі әрекеттерді орындамайды, бірақ бұл орындауды жүзеге асыруға береді. Бұл үлгі көбінесе «басқару» кластары және «платформа» кластарының бірнеше түрі (мысалы, Windows, Linux және т.б.) болғанда қолданылады. Бұл тәсілмен осы иерархияның бірі (абстракция) басқа иерархияның (іске асыру) an objectілеріне сілтеме алады және оларға негізгі жұмысты тапсырады. Барлық енгізулер ортақ интерфейске сәйкес келетіндіктен, оларды абстракция ішінде ауыстыруға болады. Java тілінде мұның айқын мысалы java.awt:
Java тіліндегі дизайн үлгілері - 5
Қосымша ақпарат алу үшін « Java AWT үлгілері » мақаласын қараңыз . Құрылымдық үлгілердің ішінде мен « Қасбет » үлгісін де атап өткім келеді . Оның мәні ыңғайлы және қысқа интерфейстің артында осы API артындағы кітапханаларды/жақтауларды пайдаланудың күрделілігін жасыру болып табылады. Мысалы, мысал ретінде JPA жүйесінен JSF немесе EntityManager пайдалана аласыз. Сондай-ақ « Ұшқан салмақ » деп аталатын тағы бір үлгі бар . Оның мәні мынада: егер әртүрлі an objectілер бірдей күйге ие болса, онда оны жалпылауға және әр an objectіде емес, бір жерде сақтауға болады. Содан кейін әрбір нысан жалпы бөлікке сілтеме жасай алады, бұл сақтау үшін жад шығындарын азайтады. Бұл үлгі көбінесе алдын ала кэштеуді немесе нысандар пулын қолдауды қамтиды. Бір қызығы, біз бұл үлгіні басынан бастап білеміз:
Java тіліндегі дизайн үлгілері - 6
Сол ұқсастық бойынша жолдар пулын осында қосуға болады. Сіз осы тақырып бойынша мақаланы оқи аласыз: « Ұшқан салмақты дизайн үлгісі ».
Java тіліндегі дизайн үлгілері - 7

Мінез-құлық үлгілері

Сонымен, біз нысандарды қалай жасауға болатынын және сыныптар арасындағы байланыстарды қалай ұйымдастыруға болатынын анықтадық. Қалған ең қызықты нәрсе - нысандардың әрекетін өзгерту икемділігін қамтамасыз ету. Бұл бізге мінез-құлық үлгілері көмектеседі. Ең жиі айтылатын үлгілердің бірі – « Стратегия » үлгісі. Дәл осы жерден « Алдымен бас. Дизайн үлгілері » кітабындағы өрнектерді зерттеу басталады. «Стратегия» үлгісін пайдалана отырып, біз 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ісін өзгерте аламыз. Ал негізгі нысаннан мемлекетке шақыруларды шақыру. Java тілінің негіздерін зерттеуден бізге белгілі тағы бір үлгі – « Команда » үлгісі. Бұл дизайн үлгісі әртүрлі пәрмендерді әртүрлі сыныптар ретінде ұсынуға болатындығын көрсетеді. Бұл үлгі Стратегия үлгісіне өте ұқсас. Бірақ Стратегия үлгісінде біз нақты әрекеттің қалай орындалатынын қайта анықтадық (мысалы, ішінде сұрыптау 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();
  }
}
Көріп отырғаныңыздай, пәрмен жаңа ағында орындалатын әрекетті немесе пәрменді анықтайды. « Жауапкершілік тізбегі» үлгісін де қарастырған жөн . Бұл үлгі де өте қарапайым. Бұл үлгіде бірдеңені өңдеу қажет болса, өңдеушілерді тізбекте жинауға болады. Мысалы, бұл үлгі веб-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");
  }
}
Көріп отырғаныңыздай, өңдеушілер тіркеуші өңдеушілер тізіміне қосылған. Тіркеуші өңдеу үшін хабарлама алған кезде, әрбір осындай хабарлама сол тіркеуші үшін өңдеушілер тізбегі (-ден 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());
    }
  }
}
Көріп отырғаныңыздай, итератор жинақтың бөлігі емес, коллекцияны айналып өтетін бөлек сыныппен ұсынылған. Итератордың пайдаланушысы оның қандай жинақта қайталанатынын білмеуі мүмкін, яғни. ол қандай коллекцияға барады? « Келуші » үлгісін қарастырған жөн . Келуші үлгісі итератор үлгісіне өте ұқсас. Бұл үлгі нысандардың құрылымын айналып өтуге және осы нысандарда әрекеттерді орындауға көмектеседі. Олар тұжырымдамасы бойынша біршама ерекшеленеді. Итератор коллекцияны айналып өтеді, осылайша итераторды пайдаланатын клиент жинақтың ішінде не екені маңызды емес, тек реттегі элементтер маңызды. Келуші біз баратын нысандардың белгілі бір иерархиясы немесе құрылымы бар екенін білдіреді. Мысалы, біз бөлек каталогты өңдеуді және бөлек файлды өңдеуді пайдалана аламыз. 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ілерде болып жатқан оқиғаларды бақылауға және оларға жауап беруге мүмкіндік беретін жазылу механизмін қамтамасыз ету. Бұл үлгі әртүрлі оқиғаларға жауап беретін әртүрлі тыңдаушылар мен бақылаушыларда жиі қолданылады. Қарапайым мысал ретінде JDK бірінші нұсқасынан осы үлгінің орындалуын еске түсіруге болады:
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імен әрекеттесеміз. Сырттай ол «Қасбетке» өте ұқсас болып көрінуі мүмкін. Бірақ айырмашылығы Фасадты пайдаланған кезде компоненттер қасбеттің бар екенін білмейді және бір-бірімен сөйлеседі. Ал «Медиатор» қолданылғанда құрамдас бөліктер делдалды біледі және пайдаланады, бірақ бір-бірімен тікелей байланыспайды. « Үлгі әдісі » үлгісін қарастырған жөн.Үлгі оның атынан түсінікті. Қорытындысы: code 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 тіліндегі дизайн үлгілері - 8

Қорытынды

Шолудан көргеніміздей, үлгілердің алуан түрлілігі бар. Олардың әрқайсысы өз мәселесін шешеді. Және бұл үлгілерді білу жүйеңізді икемді, техникалық қызмет көрсетуге болатын және өзгерістерге төзімді болу үшін қалай жазу керектігін уақытында түсінуге көмектеседі. Ақырында, тереңірек сүңгу үшін кейбір сілтемелер: #Вячеслав
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION