Главная страница
Навигация по странице:

  • «отложенная инициализация»

  • Рабочая программа по дисциплине Цели и задачи освоения дисциплины Дисциплина Объектноориентированный анализ и программирование


    Скачать 339.98 Kb.
    НазваниеРабочая программа по дисциплине Цели и задачи освоения дисциплины Дисциплина Объектноориентированный анализ и программирование
    Дата12.10.2022
    Размер339.98 Kb.
    Формат файлаdocx
    Имя файлаobektno-orientirovannyj_analiz_i_programmirovanie_161021.docx
    ТипРабочая программа
    #730141
    страница9 из 14
    1   ...   6   7   8   9   10   11   12   13   14
    public static void main(String . args) {

    intCl data = {3, 2, 1, 5, 4};

    SorterGenerator sg new AscendingBubbleSorterGenerator();

    Sorter s = sg.getSorter() ;

    s.sort(data);

    print(data);

    sg new DescendingBubbleSorterGenerator();

    s = sg.getSorter();

    s.sort(data);

    print(data);

    В данном примере классы AscendingBubbleSortcrGcnerator и DescendingBubblcSorterGenerator реализуют интерфейс SorterGenerator, включающий в себя единственный метод getSorter(), который в свою очередь возвращает экземпляр класса, реализующего интерфейс Sorter. Примерами таких классов служат AscendingBubbleSorter и DcscendingBubbleSorter: первый из них позволяет выполняет сортировку массива целых чисел по возрастанию, второй — но убыванию. Класс Client, используя возможности обоих, упорядочивает набор чисел, выводя результат на экран.

    Строитель

    Похожим на «фабричный метод» является «строитель» — порождающий шаблон проектирования, который отделяет конструирование сложного объекта от его представления. Таким образом, в результате одного и того же процесса конструирования могут получиться разные представления. По сути, строитель — это «половинка фабричного метода», отвечающая за создание классов-продуктов.

    Среди основных преимуществ данного шаблона особенно стоит отмстить следующие.

    • Возможность изменить внутреннее представление продукта. Так как продукт конструируется через абстрактный интерфейс, то для изменения внутреннего представления продукта достаточно всего лишь определить новый вид строителя.

    • Изоляция кода, реализующего конструирование и представление, от клиентов, которым нет необходимости знать что-то о внутренней структуре продукта (принцип инкапсуляции).

    • Более тонкий контроль надо процессом конструирования. В отличие от других порождающих шаблонов, здесь процесс конструирования осуществляется шаг за шагом, что обеспечивает лучший контроль над процессом и внутренней структурой продукта.

    Рассмотрим пример.

    import java.util.Random

    public class Point {

    private int x, y;

    public Point() { this.x = 0; this.у = 0;

    public void setX(int x) {

    this.x = x;

    }

    public void setY(int y) {

    this.у = у;

    System.out.printin("X = " + х + "; Y = " + у);

    System.out.flush();

    public interface Builder { void buildPart(Point pnt); }

    public class BuilderX implements Builder {

    public void buildPart(Point pnt) { Random rnd new Random(); pnt.setX(rnd.nextInt(100) + 1) ; } }

    public class BuilderY implements Builder {

    public void buildPart(Point pnt) { Random rnd new Random(); pnt.setY(rnd.next!nt(100) + 1) ; }

    }

    public class Client {

    private Builder bl, b2;

    public Client(Builder bl, Builder b2) { this.bl = bl; this.b2 = b2;

    }

    public Point construct() {

    Point pnt new Point();

    bl.buildPart(pnt);

    b2.buildPart(pnt);

    return pnt;

    }

    public static void main(String . args) {

    Client cl new Client(new BuilderX(), new BuilderY()); for(int i = 0; i < 5; i++)

    cl.construct().print();

    В предлагаемом примере классы BuilderX и BuilderY реализуют интерфейс Builder, декларирующий метод buildPart. Класс Client посредством метода construed) способен создавать экземпляр Point. При создании объекта подклассы типа Builder определяют координаты создаваемой точки. Текущий набор строителей генерирует точку, расположенную в первой четверти координатной плоскости. Для изменения места расположения генерируемой точки достаточно заменить один подкласс (или оба) Builder класса Client. Метод print() класса Point выводит на экран информацию о созданной сущности.

    Основным преимуществом над «фабричным методом» является то, что «ст роитель» придает процессу создания класса большую гибкость.

    Отложенная инициализация

    Чрезвычайно полезным на практике является шаблон отложенной инициализации. В его основе лежит предложенный Веллманом при развитии парадигмы динамического программирования принцип отложенной операции — составной части ленивого программирования. Идея этого принципа заключается в том, что некоторая ресурсоемкая задача выполняется только в тот момент, когда потребуется ее результат.

    Частный случай отложенной операции — порождающий шаблон проектирования «отложенная инициализация» — создание объекта в момент первого обращения к нему. При использовании данного шаблона инициализация объекта выполняется только в тех случаях, когда она действительно необходима. Так как инстанцирование объектов чаще всего выполняется не в момент старта приложения, то таким образом достигается ускорение начальной инициализации. Однако, при обращении к объекту в первый раз возникает задержка, обусловленная процессом созданием объекта. Пожалуй, основным недостатком является то, что шаблон не позволяет явным образом задать порядок инициализации.

    Вернемся к примеру с классами Datastorage и BubbleSorter. Очевидно, что сортировка хранимых в Datastorage данных может потребоваться нс во всех случаях, поэтому правильнее будет создавать экземпляр объекта BubbleSorter только в момент вызова метода sort().

    public class BubbleSorter {

    private static BubbleSorter instance = null;

    public static BubbleSorter getlnstance() { synchronized (BubbleSorter.c^ass) { if(instance null)

    instance new BubbleSorter();

    return instance;

    public void sort(int.. args) {

    public class Datastorage { private int .. data;

    public int [ J getDataO {

    public void sort() {

    public void sort() {

    if(data != null)

    Bubblesorter.getlnstance().sort(data);

    public static void main (String/ args) {

    //. .

    }

    Новая реализация BubbleSorter предусматривает наличие статического поля instance, представляющего собой ссылку на экземпляр класса BubbleSorter. С помощью статического метода getlnstanceO клиентские классы могут получить доступ к полю instance. При этом работа всего класса основана на принципе ленивого программирования: пока кому-либо не понадобится сущность BubbleSorter, экземпляр не будет создан. Однако после первого обращения и выполнения инициализации ссылка на созданный объект будет сохранена в иоле instance, и последующее обращение нс повлечет повторную инициализацию. Предлагаемая реализация с технической точки зрения является более правильной, так как помимо прочего клиентские объекты получают доступ к одному и тому же экземпляру BubbleSorter. Такое решение не сказывается на функциональности и производительност и, однако, позволяет «не плодить сущности без надобности».

    Одиночка

    Представленный пример имеет много общего с другим шаблоном проектирования — «одиночкой». Такое название получил порождающий шаблон, который гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа. Важным является то, что работа осуществляется с экземпляром класса, так как это позволят пользоваться расширенной функциональностью в сравнении со статическими классами.

    Положительными эффектами, связанными с применением «одиночки», является уменьшение числа имен в адресном пространстве и предоставление глобальной точки доступа. Однако частое использование глобальных объектов приводит к созданию немасштабируемых приложений, а также усложняет написание комплексных тестов.

    Типичным примером использования «одиночки» является логгер — специализированный класс, предназначенный для запоминания последовательности действий, совершаемых пользователем при работе с приложением. В случае неожиданного сбоя эта последовательность может быть использована для воспроизведения проблемной ситуации с целью определения и устранения се причин.

    import java.util.InputMismatchException;

    import java.util.Scanner;

    private volatile static Logger instance;

    public static Logger getlnstance() { if(instance null) { synchronized(Logger.class) { if(instance null) { instance new Logger();

    return instance;

    public void print(String arg) {

    System.out.printin(arg) ;

    System.out.flush ();

    public class Client {

    public static void main(String[] args) { Scanner in new Scanner(System.in); System.out.printin("Введите число: "); try { int x = in.nextlnt();

    Logger.getlnstance().print("Пользователь ввел число " + x) ;

    catch (InputMismatchException e) {

    Logger.getlnstance().print("Пользователь ввел не число");

    В представленном примере класс Logger как раз и является тем «одиночкой», который позволяет документировать события, происходящие в приложении. Метод getlnstance() необходим для получения ссылки на экземпляр класса (используется ленивая инициализация). Метод print(Slring arg) может быть вызван из любого участка приложения для вывода строки-аргумента на экран. Пример использования возможностей Logger приведен в методе main класса Client.

    Прототип

    Последним рассматриваемым в данном разделе шаблоном будет «прототип» — порождающий шаблон проектирования, который задает вид создаваемых объектов. Новые объекты создаются с помощью копирования этого прототипа через клонирование, а не с помощью конструктора.

    Абстрактно «прототип» может быть представлен в виде диаграммы классов.

    Интерфейс Prototype объявляет метод клонирования объектом самого себя. Классы

    ConcreteProtolypeA и

    Concrete Prototype В реализуют интерфейс Prototype. Client имеет копию экземпляра прототипа и в случае необходимости может создать произвольное количество копий данного класса посредством метода makeCopyO.

    Рассматриваемый шаблон обладает рядом важных особенностей. Во-первых, «прототип» позволяет специфицировать новые объекты путем изменения значений. Иными словами, поведение объекта может быть изменено не с помощью создания нового экземпляра класса, а путем задания переменных объекта. Во-вторых, использование шаблона способствует сокращению числа подклассов. Например, шаблон «фабричный метод» часто порождает иерархию классов-создателей, параллельную основной иерархии классов-продуктов. «Прототип» позволяет создавать новый объект через клонирование, а не через запрос к фабричному методу. Таким образом, иерархия классов-создателей становится не нужной. В-третьих, с помощью «прототипа» становится возможным динамическое конфигурирование приложения классами, то есть он позволяет организовать динамическую загрузку классов в приложение во время его выполнения. Java имеет практически встроенную поддержку данного шаблона. Дело в том, что в стандартную библиотеку JavaAPI входит интерфейс Cloneable. Каждый экземпляр класса, реализующего этот интерфейс, может быть продублирован с помощью метода clone(). Таким образом, для организации «прототипа» в собственном java-приложении нет необходимости в описании отдельного интерфейса.

    Структурные шаблоны

    Адаптер

    Наиболее часто применяемым на практике является шаблон «адаптер» — структурный шаблон проектирования, предназначенный для преобразования интерфейса одного класса в интерфейс другого класса. Шаблон может помочь в тех случаях, когда возникает необходимость использовать готовый сторонний или ранее разработанный класс, однако его интерфейс не соответствует потребностям. Иными словами, «адаптер» позволяет повысить степень повторного используемост и кода.

    Типичным примером шаблона может служить следующий код.

    public class SequencesProcessor {

    1   ...   6   7   8   9   10   11   12   13   14


    написать администратору сайта