Статьи

Пример фабричного проектирования

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

Как этот код, это та часть, которую я нашел в нашем коде.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public ContactInfoBean(final Reseller resellerInfo) {
 
       switch(resellerInfo.getType()) {
 
           case PROGRAM_CONTACT:
 
               readExecutiveInfo(resellerInfo);
 
               break;
 
           case FILE_CONTACT:
 
               readOperationalInfo(resellerInfo);
 
               break;
 
           default:
 
               break;
 
       }
 
   }

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

Лучший подход к ООП

Что ж, лучшим подходом для описанного выше случая будет использование шаблона Factory Design. Мы можем позволить фабрике READER генерировать каждый экземпляр в соответствии с его типом. Было бы проще вырастить тип экземпляра, поскольку нам просто нужно создать новый класс и сделать небольшую модификацию в классе Factory. Класс вызывающего абонента не будет расти и будет стоять в своей текущей форме.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface InfoReader {
 
 public void readInfo();
 
}
public class ExecutiveReader implements InfoReader {
 
 public void readInfo() {
 
  // override
 
 }
 
}
public class OperationalReader implements InfoReader {
 
 public void readInfo() {
 
  // override
 
 }
 
}

И фабрика

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
public class InfoReaderFactory {
 
 private static final int PROGRAM_CONTACT = 1;
 
 private static final int FILE_CONTACT = 2;
 
 public static InfoReader getInstance(Reseller resellerInfo) {
 
  InfoReader instance = null;
 
  switch (resellerInfo.getType()) {
 
  case PROGRAM_CONTACT:
 
   instance = new ExecutiveReader();
 
   break;
 
  case FILE_CONTACT:
 
   instance = new OperationalReader();
 
   break;
 
  default:
 
   throw new IllegalArgumentException('Unknown Reseller');
 
  }
 
  return instance;
 
 }
 
}

А теперь Звонящий

1
2
3
InfoReader reader = InfoReaderFactory.getInstance(resellerInfo);
 
reader.readInfo();

Выгоды

С помощью Factory Design Pattern, чтобы справиться с этим делом, мы можем добиться некоторых преимуществ,

  • Указание класса для одной задачи означает, что его легче поддерживать, поскольку один класс предназначен только для одной цели (модульность / высокая сплоченность). То есть: Оперативный Считыватель предназначен только для чтения данных только для Оперативного, без других целей. На всякий случай, однажды в будущем нам понадобится другой Reader (скажем, NonOperationalReader). Нам просто нужно создать новый класс, который расширяет (или реализует) класс InfoReader, а затем мы можем переопределить нашу собственную функцию readInfo (). Этот класс абонентов не будет иметь никакого влияния. Нам просто нужно внести некоторые изменения в коде Factory.
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
public class InfoReaderFactory {
 
 private static final int PROGRAM_CONTACT = 1;
 
 private static final int FILE_CONTACT = 2;
 
 private static final int NEW_READER = 3;
 
 public static InfoReader getInstance(ResellerInfo resellerInfo) {
 
  InfoReader instance = null;
 
  switch (resellerInfo.getType()) {
 
  case PROGRAM_CONTACT:
 
   instance = new ExecutiveReader();
 
   break;
 
  case FILE_CONTACT:
 
   instance = new OperationalReader();
 
   break;
 
  case NEW_READER:
 
   instance = new NonOperationalReader();
 
   break;
 
  default:
 
   throw new IllegalArgumentException('Unknown Reseller');
 
  }
 
  return instance;
 
 }
 
}
  • Более высокая возможность повторного использования родительского компонента (наследование): поскольку у нас есть родительский класс (InfoReader), мы можем поместить общие функции и вещи в этот класс InfoReader, а позже все производные классы (ExecutiveReader и OperationalReader) могут повторно использовать общие компоненты из InfoReader. Избегайте избыточности кода и можете минимизировать время кодирования. Хотя это зависит от того, как вы делаете код и не может быть гарантировано.

Но, это работает отлично, мы должны изменить это?

Очевидно, ответ большой НЕТ. Это только тематическое исследование и для вашего дальнейшего опыта и знаний. ООП это хорошо, делай это где угодно. Но самое главное, если он работает, не меняйте его. Было бы смешно, если бы вы испортили весь рабочий код просто для того, чтобы следовать ООП-подходу. Не будь наивным, никто не может достичь идеального кода. Самое главное, мы знаем, какой подход лучше.

Ссылка: Пример из практики: Шаблон дизайна фабрики от нашего партнера JCG Рональда Джунаеди в блоге Naming Exception .