Статьи

Пример шаблона дизайна шаблона

Эта статья является частью нашего курса Академии под названием « Шаблоны проектирования Java» .

В этом курсе вы изучите огромное количество шаблонов проектирования и увидите, как они реализуются и используются в Java. Вы поймете причины, почему шаблоны так важны, и узнаете, когда и как применять каждый из них. Проверьте это здесь !

1. Введение

Шаблон дизайна шаблона является шаблоном поведения и, как следует из названия, он предоставляет шаблон или структуру алгоритма, который используется пользователями. Пользователь предоставляет собственную реализацию без изменения структуры алгоритма.

Этот паттерн легче понять с помощью проблемы. Мы поймем сценарий в этом разделе и реализуем решение, используя шаблон шаблона в следующем разделе.

Вы когда-нибудь подключались к базе данных отношений, используя свое Java-приложение? Давайте вспомним некоторые важные шаги, которые необходимы для подключения и вставки данных в базу данных. Во-первых, нам нужен драйвер в соответствии с базой данных, с которой мы хотим соединиться. Затем мы передаем некоторые учетные данные в базу данных, затем готовим оператор, устанавливаем данные в оператор вставки и вставляем его с помощью команды вставки. Позже мы закрываем все соединения и при необходимости уничтожаем все объекты соединения.

Вам необходимо написать все эти шаги независимо от реляционной базы данных любого поставщика. Рассмотрим проблему, когда вам нужно вставить некоторые данные в разные базы данных. Вам нужно извлечь некоторые данные из файла CSV и вставить их в базу данных MySQL. Некоторые данные поступают из текстового файла и должны быть вставлены в базу данных Oracle. Единственная разница — это драйвер и данные, остальные шаги должны быть одинаковыми, поскольку JDBC предоставляет общий набор интерфейсов для связи с конкретной базой данных отношений любого поставщика.

Мы можем создать шаблон, который будет выполнять некоторые шаги для клиента, и мы оставим некоторые шаги, чтобы позволить клиенту реализовать их по-своему. При желании клиент может переопределить поведение по умолчанию некоторых уже определенных шагов.

Теперь, прежде чем приступить к реализации кода, давайте узнаем больше о шаблонах проектирования шаблонов.

2. Что такое шаблон дизайна шаблона

Шаблон шаблона определяет каркас алгоритма в операции, откладывая некоторые шаги до подклассов. Шаблонный метод позволяет подклассам переопределять определенные этапы алгоритма без изменения структуры алгоритма.

Шаблон Template Method может использоваться в ситуациях, когда существует алгоритм, некоторые этапы которого могут быть реализованы несколькими различными способами. В таких сценариях шаблонный шаблонный метод предлагает сохранить схему алгоритма в отдельном методе, называемом методическим шаблоном, внутри класса, который может называться классовым шаблоном, исключая конкретные реализации вариантов частей (этапы которые могут быть реализованы несколькими различными способами) алгоритма для различных подклассов этого класса.

Класс Template не обязательно должен оставлять реализацию полностью подклассам. Вместо этого, как часть схемы алгоритма, класс Template может также обеспечить некоторую реализацию, которую можно рассматривать как инвариантную для разных реализаций. Он может даже обеспечить реализацию по умолчанию для вариантов частей, если это необходимо. Только конкретные детали будут реализованы внутри разных подклассов. Этот тип реализации устраняет необходимость дублирования кода, что означает минимальный объем кода, который должен быть написан.

Рисунок 1 - Диаграмма классов

фигура 1

AbstractClass

  • Определяет абстрактные примитивные операции, которые определяют конкретные подклассы для реализации шагов алгоритма.
  • Реализует шаблонный метод, определяющий каркас алгоритма. Метод шаблона вызывает простые операции, а также операции, определенные в AbstractClass или других объектах.
    ConcreteClass
  • Реализует примитивные операции для переноса.

3. Реализация шаблона дизайна шаблона

Ниже мы видим класс шаблона подключения, используемый для предоставления клиентам шаблона для подключения и взаимодействия с различными базами данных.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.javacodegeeks.patterns.templatepattern;
 
public abstract class ConnectionTemplate {
 
    public final void run() {
        setDBDriver();
        setCredentials();
        connect();
        prepareStatement();
        setData();
        insert();
        close();
        destroy();
    }
 
    public abstract void setDBDriver();
 
    public abstract void setCredentials();
 
    public void connect() {
        System.out.println("Setting connection...");
    }
 
    public void prepareStatement() {
        System.out.println("Preparing insert statement...");
    }
 
    public abstract void setData();
 
    public void insert() {
        System.out.println("Inserting data...");
    }
 
    public void close() {
        System.out.println("Closing connections...");
    }
 
    public void destroy() {
        System.out.println("Destroying connection objects...");
    }
}

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

Метод setDBDriver должен реализовываться пользователем для предоставления драйверов, специфичных для базы данных. Полномочия могут быть разными для разных баз данных; следовательно, setCredentials также оставлен как абстрактный, чтобы позволить пользователю реализовать его.

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

Ключевым методом вышеприведенного класса является метод run . Метод run используется для выполнения этих шагов по порядку. Метод установлен как окончательный, потому что шаги должны быть безопасными и не должны быть изменены любым пользователем.

Два следующих класса расширяют класс шаблона и предоставляют конкретную реализацию некоторым методам.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package com.javacodegeeks.patterns.templatepattern;
 
public class MySqLCSVCon extends ConnectionTemplate {
 
    @Override
    public void setDBDriver() {
        System.out.println("Setting MySQL DB drivers...");
    }
 
    @Override
    public void setCredentials() {
        System.out.println("Setting credentials for MySQL DB...");
    }
 
    @Override
    public void setData() {
        System.out.println("Setting up data from csv file....");
    }
}

Приведенный выше класс используется для подключения к базе данных MySQL и предоставляет данные путем чтения файла CSV.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package com.javacodegeeks.patterns.templatepattern;
 
public class OracleTxtCon extends ConnectionTemplate {
 
    @Override
    public void setDBDriver() {
        System.out.println("Setting Oracle DB drivers...");
    }
 
    @Override
    public void setCredentials() {
        System.out.println("Setting credentials for Oracle DB...");
    }
 
    @Override
    public void setData() {
        System.out.println("Setting up data from txt file....");
    }
}

Приведенный выше класс используется для подключения к базе данных Oracle и предоставляет данные путем чтения текстового файла.

Теперь давайте проверим код.

01
02
03
04
05
06
07
08
09
10
11
12
13
package com.javacodegeeks.patterns.templatepattern;
 
public class TestTemplatePattern {
 
    public static void main(String[] args) {
        System.out.println("For MYSQL....");
        ConnectionTemplate template = new MySqLCSVCon();
        template.run();
        System.out.println("For Oracle...");
        template = new OracleTxtCon();
        template.run();
    }
}

Приведенный выше код приведет к следующему выводу:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
For MYSQL....
Setting MySQL DB drivers...
Setting credentials for MySQL DB...
Setting connection...
Preparing insert statement...
Setting up data from csv file....
Inserting data...
Closing connections...
Destroying connection objects...
 
For Oracle...
Setting Oracle DB drivers...
Setting credentials for Oracle DB...
Setting connection...
Preparing insert statement...
Setting up data from txt file....
Inserting data...
Closing connections...
Destroying connection objects...

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

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

4. Введение крючка в шаблон

Давайте улучшим приведенный выше пример с помощью хука.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.javacodegeeks.patterns.templatepattern;
 
import java.util.Date;
 
public abstract class ConnectionTemplate {
 
    private boolean isLoggingEnable = true;
 
    public ConnectionTemplate() {
        isLoggingEnable = disableLogging();
    }
 
    public final void run() {
        setDBDriver();
        logging("Drivers set [" + new Date() + "]");
        setCredentials();
        logging("Credentails set [" + new Date() + "]");
        connect();
        logging("Conencted");
        prepareStatement();
        logging("Statement prepared [" + new Date() + "]");
        setData();
        logging("Data set [" + new Date() + "]");
        insert();
        logging("Inserted [" + new Date() + "]");
        close();
        logging("Conenctions closed [" + new Date() + "]");
        destroy();
        logging("Object destoryed [" + new Date() + "]");
    }
 
    public abstract void setDBDriver();
 
    public abstract void setCredentials();
 
    public void connect() {
        System.out.println("Setting connection...");
    }
 
    public void prepareStatement() {
        System.out.println("Preparing insert statement...");
    }
 
    public abstract void setData();
 
    public void insert() {
        System.out.println("Inserting data...");
    }
 
    public void close() {
        System.out.println("Closing connections...");
    }
 
    public void destroy() {
        System.out.println("Destroying connection objects...");
    }
 
    public boolean disableLogging() {
        return true;
    }
 
    private void logging(String msg) {
        if (isLoggingEnable) {
            System.out.println("Logging....: " + msg);
        }
    }
}

Мы ввели два новых метода внутри класса шаблона выше. disableLogging — это ловушка, которая возвращает boolean . По умолчанию логическое значение isLoggingEnable , которое включает ведение журнала, имеет значение true. Пользователь может переопределить этот метод, если ведение журнала должно быть отключено для его кода. Другой — приватный метод, используемый для регистрации сообщений.

Приведенный ниже класс реализует метод ловушки и возвращает false, что отключает механизм ведения журнала для этой конкретной работы.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.javacodegeeks.patterns.templatepattern;
 
public class MySqLCSVCon extends ConnectionTemplate {
 
    @Override
    public void setDBDriver() {
        System.out.println("Setting MySQL DB drivers...");
    }
 
    @Override
    public void setCredentials() {
        System.out.println("Setting credentials for MySQL DB...");
    }
 
    @Override
    public void setData() {
        System.out.println("Setting up data from csv file....");
    }
 
    @Override
    public boolean disableLogging() {
        return false;
    }
}

Давайте проверим этот код.

01
02
03
04
05
06
07
08
09
10
11
12
package com.javacodegeeks.patterns.templatepattern;
 
public class TestTemplatePattern {
    public static void main(String[] args) {
        System.out.println("For MYSQL....");
        ConnectionTemplate template = new MySqLCSVCon();
        template.run();
        System.out.println("For Oracle...");
        template = new OracleTxtCon();
        template.run();
    }
}

Приведенный выше класс приведет к следующему выводу:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
For MYSQL....
Setting MySQL DB drivers...
Setting credentials for MySQL DB...
Setting connection...
Preparing insert statement...
Setting up data from csv file....
Inserting data...
Closing connections...
Destroying connection objects...
 
For Oracle...
Setting Oracle DB drivers...
Logging....: Drivers set [Sat Nov 08 23:53:47 IST 2014]
Setting credentials for Oracle DB...
Logging....: Credentails set [Sat Nov 08 23:53:47 IST 2014]
Setting connection...
Logging....: Conencted
Preparing insert statement...
Logging....: Statement prepared [Sat Nov 08 23:53:47 IST 2014]
Setting up data from txt file....
Logging....: Data set [Sat Nov 08 23:53:47 IST 2014]
Inserting data...
Logging....: Inserted [Sat Nov 08 23:53:47 IST 2014]
Closing connections...
Logging....: Conenctions closed [Sat Nov 08 23:53:47 IST 2014]
Destroying connection objects...
Logging....: Object destoryed [Sat Nov 08 23:53:47 IST 2014]

В выходных данных ясно видно, что ведение журнала отключено для реализации MySQL, а для реализации Oracle включено.

5. Когда использовать шаблон дизайна шаблона

Шаблон Template Method следует использовать в следующих случаях:

  • Один раз реализовать инвариантные части алгоритма и оставить его на усмотрение подклассов, чтобы реализовать поведение, которое может меняться.
  • Когда общее поведение среди подклассов должно быть учтено и локализовано в общем классе, чтобы избежать дублирования кода. Сначала вы определяете различия в существующем коде, а затем разделяете различия на новые операции. Наконец, вы заменяете другой код на шаблонный метод, который вызывает одну из этих новых операций.
  • Контролировать расширения подклассов. Вы можете определить шаблонный метод, который вызывает операции «ловушки» (см. Последствия) в определенных точках, тем самым разрешая расширения только в этих точках.

6. Шаблон шаблона в JDK

  • java.util.Collections#sort()
  • java.io.InputStream#skip()
  • java.io.InputStream#read()
  • java.util.AbstractList#indexOf()

7. Загрузите исходный код

Это был урок по шаблону дизайна шаблона. Вы можете скачать исходный код здесь: TemplatePattern-Project