Принцип відкритості/закритості

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Принцип відкритості/закритості (англ. Open Closed Principle, OCP) — важливий принцип об'єктно-орієнтованого програмування, який означає, що «програмні сутності, такі як класи, модулі, функції, методи та ін. мають бути відкритими для розширення та закритими для змін». Це означає, що вони можуть надавати можливість змінювати свою поведінку без або з мінімальними змінами коду.

Дослідження показали, що всі найкращі проектувальники можуть передбачати зміни.[1]

Тому при проєктуванні системи необхідно закласти в неї можливість безболісного додавання функціоналу чи його зміни.

Історія

[ред. | ред. код]

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

Принцип відкритості/закритості Мейєра

[ред. | ред. код]

Бертран Мейєр відомий як основоположник терміну «принцип відкритості/закритості», що з'явився в 1988 році в його книзі «Object-Oriented Software Construction[en]». Ідея полягала в тому, що розроблена реалізація класу в подальшому вимагає лише виправлення помилок, а нові чи змінені функції вимагають створення нового класу. Він може використовувати код предка завдяки механізму успадкування, але не обов'язково слідує його інтерфейсу. Очевидно, що визначення Мейєра підтримує ідею «успадкування реалізації».

Поліморфний принцип відкритості/закритості

[ред. | ред. код]

У 1990-х принцип відкритості/закритості став де-факто перевизначений для застосування з абстрактними інтерфейсами, реалізації яких можуть бути як змінені, так і поліморфно підмінені.

На відміну від ідей Мейєра, це визначення підтримує ідею «Успадкування від абстрактних класів». Специфікації інтерфейсів можуть бути успадкувані, проте реалізація має лишатися незмінною. Існуючий інтерфейс має бути закритий для модифікацій, а нові реалізації мусять його реалізовувати. Однією з публікацій, що популяризувала такий підхід, була стаття Роберта Мартіна «The Open-Closed Principle»[2].

Приклад порушення OCP

[ред. | ред. код]

Нехай у системі є клас спортивного парсера для створення різних об'єктів SportInfo, що інкапсулюють різну інформацію про гру:

public class BadParserRealization {
   public SportInfo parse(String[] data) {
      SportInfo result;
      if (data[0].equals("nba")) {
         // код для аналізу NBA
      } else {
         if (data[0].equals("nhl")) {
            // код для аналізу NHL
         }
      }
      return result;
   }
}

На перший погляд все нормально, проте при спробі додати нову лігу, наприклад MLB, виникнуть проблеми. Програмісти будуть змушені редагувати parse(String[] data), і, можливо, зачеплять робочий код.

Ця проблема легко вирішується застосуванням шаблону проєктування «Будівник». Рішення може бути таким:

public class BetterParserRealization {
   private Map<String, SportInfoBuilder> builders;

   public BetterParserRealization(Map<String, SportInfoBuilder> builders) {
         setBuilders(builders);
   }

   public void setBuilders(Map<String, SportInfoBuilder> builders) {
         if (builders == null) {
            throw new NullPointerException("Builders can not be null!");
         }
         this.builders = builders;
   }

   public void parse(String[] data) {
      SportInfoBuilder builder = builders.get(data[0]);
      builder.build(data);
      return builder.getResult();
   }
}
public interface SportInfoBuilder {
   public void build(String[] data);
}
public class NBASportInfoBuilder implements SportInfoBuilder {
   private SportInfo result;

   @Override
   public void build(String[] data) {
      // код для аналізу NBA
   }

   public SportInfo getResult() {
      return result;
   }
}

Спочатку визначається парсер, що може обробити вхідний масив. Відношення між ним та лігою встановлюється іншим класом (це може бути шаблон проєктування абстрактна фабрика або IoC контейнер). Варто зазначити, що при додаванні нової ліги, потреби в редагуванні вже робочого коду відпадають, натомість необхідно створити новий клас, що буде реалізовувати інтерфейс SportInfoBuilder.

Переваги та недоліки

[ред. | ред. код]

Перевагою використання цього принципу є те, що він дозволяє додавати новий функціонал без редагування вже написаного коду, отже система стає гнучкою та легко супроводжується. Недолік полягає в зростанні кількості класів, що приводить до зростання складності системи.

Використання

[ред. | ред. код]

SOLID — буква «O» означає принцип відкритості/закритості (англ. Open Closed Principle).

OCP та SRP

[ред. | ред. код]

OCP та SRP дуже близько пов'язані. Справді, адже чим більше функціональності закладено в клас, тим більша ймовірність того, що його доведеться змінювати. Тому, порушуючи SRP, програміст, найпевніше, порушує і OCP.

Примітки

[ред. | ред. код]
  1. McConnell, Steve. (1993). Code Complete. Microsoft Press. ISBN 978-1-55615-484-3.
  2. Мартін, Роберт «The Open-Closed Principle», C++ Report, January 1996

Посилання

[ред. | ред. код]