Статьи

Шаблон фабричного дизайна – эффективный подход

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

Технические детали

Как я уже говорил, мы получим подобный объект типа во время выполнения в случае фабричного дизайна, так что основная реализация объекта будет находиться за экраном. Давайте рассмотрим простой подход. Давайте рассмотрим объект Person, который может быть мужским или женским. Во время выполнения мы должны учитывать только поведение человека, а не пол. В качестве традиционного подхода мы создаем интерфейс Person и создаем два класса реализации, такие как MalePerson и FemalePerson. На основе данных пола среды выполнения мы передаем метод Factory класса Factory, где решаем, является ли тип пола Male или Female, и, соответственно, создаем экземпляр определенного класса и возвращаем объект ссылочного типа. Этот подход звучит хорошо, и мы применяем его во многих наших разработках. Можем ли мы гарантировать, что это эффективный подход в случае мелкозернистых многопоточных приложений. Как насчет производительности? Есть ли другой подход? Да.

Давайте рассмотрим другой пример в реальном времени. Подумайте о ситуации в организации, где сотрудник может быть генеральным директором, техническим директором, финансовым директором, разработчиком, инженером по тестированию, отделом кадров, персоналом, службой безопасности и т. Д. Если вы хотите узнать роль сотрудника в зависимости от организации, что вы будете делать? Как вы создадите лучший дизайн фабрики, чтобы мы могли легко найти роль, и не должно быть снижения производительности? Примете ли вы тот же традиционный подход, предложив несколько предложений if? Вы можете аргументировать, что мы должны использовать условие переключения. Хорошо … Давайте посмотрим на традиционный подход и измерим время.

Давайте использовать наш дизайн фабрики традиционным способом.

1
2
3
4
5
6
7
8
9
package com.ddlab.rnd.patterns;
/**
 * @author Debadatta Mishra(PIKU)
 *
 */
public interface Roles
{
    public String getRole();
}

Приведенный выше интерфейс используется как тип, поскольку в организации могут быть различные типы ролей. У него есть метод getRole (), который определяет описание роли сотрудника.

Давайте спроектируем классы реализации для подходящих ролей для генерального директора, технического директора и финансового директора в организации.

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
package com.ddlab.rnd.patterns;
/**
 * @author Debadatta Mishra(PIKU)
 *
 */
public class CEORoles implements Roles
{
    public String getRole()
    {
        return "CEO is the supreme head of the company";
    }
}
 
package com.ddlab.rnd.patterns;
/**
 * @author Debadatta Mishra(PIKU)
 *
 */
public class CFORoles implements Roles
{
    @Override
    public String getRole()
    {
        return "CFO is the finance head of a company";
    }
}
 
package com.ddlab.rnd.patterns;
/**
 * @author Debadatta Mishra(PIKU)
 *
 */
public class CTORoles implements Roles
{
    @Override
    public String getRole()
    {
        return "CTO is the technology decision maker of a company";
    }
}

Теперь нам нужно подумать о Фабрике, откуда мы будем динамически создавать Объект. Давайте посмотрим код ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package com.ddlab.rnd.patterns;
/**
 * @author Debadatta Mishra(PIKU)
 *
 */
public abstract class EmployeeFactory
{
    public static Roles getRole( String type )
    {
        Roles roles = null;
        if( type.equals("cfo"))
            roles = new CFORoles();
        else if( type.equals("cto"))
            roles = new CTORoles();
        else if( type.equals("ceo"))
            roles = new CEORoles();
        return roles;
    }
}

Давайте напишем простой тестовый класс для проверки конструкции.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package com.ddlab.rnd.patterns;
/**
 * @author Debadatta Mishra(PIKU)
 *
 */
public class TestTraditionalFactoryDesign
{
    public static void main(String[] args)
    {
        String type = "ceo";
        long startTime = System.nanoTime();
        String role = EmployeeFactory.getRole(type).getRole();
        System.out.println("Role ::: "+role);
        long endTime = System.nanoTime();
        System.out.println("Time difference ::: "+(endTime-startTime)+" nano seconds");
    }
 
}

Если вы запустите вышеупомянутую программу, ниже будет вывод из моей системы.

Для вашей информации, моя система имеет 4 ГБ оперативной памяти и процессор I5.

1
2
Role ::: CEO is the supreme head of the company
Time difference ::: 3477574 nano seconds

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

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

Давайте посмотрим код ниже.

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
package com.ddlab.rnd.patterns;
/**
 * @author Debadatta Mishra(PIKU)
 *
 */
public enum EmployeeType
{
    CEO("CEO")
    {
        @Override
        public Roles getRoles()
        {
            return new CEORoles();
        }
    },
 
    CTO("CTO")
    {
        @Override
        public Roles getRoles() {
 
            return new CTORoles();
        }
    },
 
    CFO("CFO")
    {
        @Override
        public Roles getRoles() {
 
            return new CFORoles();
        }
    };
 
    private EmployeeType( String type )
    {
        this.type = type;
    }
 
    private String type;
    public abstract Roles getRoles();
 
    public String getType()
    {
        return type;
    }
 
    @Override
    public String toString()
    {
        return "TYPE CODE -> "+type;
    }
}

Класс испытаний жгута приведен ниже.

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
package com.ddlab.rnd.patterns;
import java.util.HashMap;
import java.util.Map;
/**
 * @author Debadatta Mishra(PIKU)
 *
 */
public class TestFactoryDesign
{
    static Map<String,EmployeeType> typeMap = new HashMap<String,EmployeeType>();
 
    static
    {
        typeMap.put("cto", EmployeeType.CTO);
        typeMap.put("ceo", EmployeeType.CEO);
        typeMap.put("cfo", EmployeeType.CFO);
    }
 
    public static void main(String[] args)
    {
        String empType = "ceo";
        try
        {
            long startTime = System.nanoTime();
            String whatIstheRole = typeMap.get(empType).getRoles().getRole();
            System.out.println("Role of the Employee :::"+whatIstheRole);
            long endTime = System.nanoTime();
            System.out.println("Time difference ::: "+(endTime-startTime)+" nano seconds");
        }
        catch (NullPointerException e)
        {
            System.out.println("No such Role is found");
            e.printStackTrace();
        }
    }
}

Если вы запустите приведенный выше код, вы получите следующий вывод.

1
2
Role ::: CEO is the supreme head of the company
Time difference ::: 1049108 nano seconds

Как насчет времени. Позвольте использовать сравнение между временем, затраченным на традиционный подход и современный подход.

Традиционный подход 3477574 нано секунд
Современный подход (используя enum и Map) 1049108 нано секунд

Можете ли вы подумать о разнице во времени, она примерно в 3 раза быстрее, чем традиционный подход.

Так что лучше? Конечно, современный подход к использованию enum лучше. Помимо enum, я использовал Map для ведения списка типов сотрудников и соответствующих ему enum. В этом случае нет необходимости использовать условие if, которое может повлиять на нашу производительность в отношении цикломатической сложности. Всегда лучше использовать вышеуказанный подход 1049108 наносекунд. Вы можете использовать ConcurrentMap для своего многопоточного приложения.

Вывод

Надеюсь, вам понравится моя статья о фабричном дизайне. В случае каких-либо разъяснений вы можете связаться со мной debadatta.mishra@gmail.com .