Давайте попробуем поразмышлять над приведенным выше утверждением: программные сущности после написания не следует изменять для добавления новых функций, вместо этого нужно расширять их для добавления новых функций.
Другими словами, вы не затрагиваете существующие модули, тем самым не нарушая существующую функциональность, вместо этого вы расширяете модули для реализации нового требования. Таким образом, ваш код менее жесткий и хрупкий, а также расширяемый.
Термин OCP был придуман Бертнардом Мейером .
Как мы можем подтвердить принцип OCP?
Это просто — разрешить модулям (классам) зависеть от абстракций, там к новым функциям можно добавить создание новых расширений этих абстракций.
Позвольте мне попытаться объяснить на примере:
Предположим, что вы пишете модуль для утверждения личных займов, и перед тем, как вы захотите проверить личную информацию, код, мы можем представить ситуацию следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public class LoanApprovalHandler { public void approveLoan(PersonalValidator validator) { if ( validator.isValid()) { //Process the loan. } } } public class PersonalLoanValidator { public boolean isValid() { //Validation logic } } |
Все идет нормально. Как вы все знаете, требования никогда не бывают одинаковыми, и теперь требуется утверждение транспортных ссуд, потребительских ссуд, а что нет. Таким образом, один из подходов к решению этого требования заключается в
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
|
public class LoanApprovalHandler { public void approvePersonalLoan (PersonalLoanValidator validator) { if ( validator.isValid()) { //Process the loan. } } public void approveVehicleLoan (VehicleLoanValidator validator ) { if ( validator.isValid()) { //Process the loan. } } // Method for approving other loans. } public class PersonalLoanValidator { public boolean isValid() { //Validation logic } } public class VehicleLoanValidator { public boolean isValid() { //Validation logic } } |
Мы отредактировали существующий класс для соответствия новым требованиям — в процессе мы закончили тем, что изменили имя существующего метода, а также добавили новые методы для различных типов одобрения ссуды. Это явно нарушает OCP. Попробуем реализовать требование по-другому:
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
|
/** * Abstract Validator class * Extended to add different * validators for different loan type */ public abstract class Validator { public boolean isValid(); } /** * Personal loan validator */ public class PersonalLoanValidator extends Validator { public boolean isValid() { //Validation logic. } } /* * Similarly any new type of validation can * be accommodated by creating a new subclass * of Validator */ |
Теперь, используя вышеуказанные валидаторы, мы можем написать LoanApprovalHandler, чтобы использовать абстракцию Validator.
01
02
03
04
05
06
07
08
09
10
|
public class LoanApprovalHandler { public void approveLoan(Validator validator) { if ( validator.isValid()) { //Process the loan. } } } |
Таким образом, чтобы приспособиться к любому типу валидаторов ссуд, нам просто нужно создать подкласс Validator, а затем передать его в метод ApproveLoan. Таким образом, класс ЗАКРЫТ для модификации, но ОТКРЫТ для расширения.
Другой пример:
Я думал о другой гипотетической ситуации, когда использование принципа OCP может быть полезным. Ситуация выглядит примерно так: «Мы ведем список студентов с их оценками, уникальными идентификационными данными (uid) и именем. Затем мы предоставляем возможность получить процент в виде пар «имя-процент-значение». »
01
02
03
04
05
06
07
08
09
10
11
12
|
class Student { String name; double percentage; int uid; public Student(String name, double percentage, int uid) { this .name = name; this .percentage = percentage; this .uid = uid; } } |
Мы собираем список студентов в общий класс:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
class StudentBatch { private List<Student> studentList; public StudentBatch() { studentList = new ArrayList<Student>(); } public void getSutdentMarkMap(Hashtable<Integer, Double> studentMarkMap) { if (studentMarkMap == null ) { //Error } else { for (Student student : studentList) { studentMarkMap.put(student.uid, student.percentage); } } } /** * @param studentList the studentList to set */ public void setStudentList(List<Student> studentList) { this .studentList = studentList; } } |
Предположим, нам нужно поддерживать порядок элементов в Map по их порядку вставки, поэтому нам нужно написать новый метод, чтобы получить карту в порядке вставки, и для этого мы будем использовать LinkedHashMap. Вместо этого, если бы метод getStudentMarkMap () зависел от интерфейса Map, а не от конкретной реализации Hashtable, мы могли бы избежать изменения класса StudentBatch и вместо этого передать экземпляр LinkedHashMap.
1
2
3
4
5
6
7
8
9
|
public void getSutdentMarkMap(Map<Integer, Double> studentMarkMap) { if (studentMarkMap == null ) { //Error } else { for (Student student : studentList) { studentMarkMap.put(student.uid, student.percentage); } } } |
PS: я знаю, что Hashtable является устаревшей коллекцией и не рекомендуется использовать. Но я подумал, что это послужит еще одним полезным примером принципа OCP.
Некоторые способы сделать ваш код ближе к подтверждению OCP:
Делая все переменные-члены приватными, чтобы другие части кода обращались к ним через методы (геттеры), а не напрямую.
Избегание типов типов во время выполнения — это делает код хрупким и зависимым от рассматриваемых классов, что означает, что любой новый класс может потребовать редактирования метода, чтобы приспособить приведение к новому классу.
Действительно хорошая статья, написанная Робертом Мартином на OCP.
Ссылка: SOLID — принцип Open Closed от нашего партнера JCG Мохамеда Санауллы в блоге «Experiences Unlimited» .
- SOLID — принцип единой ответственности
- Фреймворки делают разработчиков глупыми?
- Не делаете Code Reviews? Какое твое оправдание?
- Почему автоматизированные тесты ускоряют вашу разработку
- Использование FindBugs для создания значительно меньшего количества ошибочного кода
- Вещи, которые должен знать каждый программист
- Список учебных пособий по Java и Android