Статьи

Твердые принципы: открытый / закрытый принцип

Ранее мы говорили о принципе единой ответственности . Принцип « открыто / закрыто» — второй в ряду принцип, касающийся аббревиатуры из твердого принципа.

«Программные объекты (классы, модули, функции и т. Д.) Должны быть открыты для расширения, но закрыты для модификации»

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

Представьте себе сценарий применения скидки на один из наших продуктов. Служба скидок применяет указанную скидку и возвращает скидку.

В настоящее время наша система имеет только один вид скидок, который распространяется на всех взрослых.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package com.gkatzioura.solid.ocp;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
 
public class Discount {
 
    public BigDecimal apply(BigDecimal price) {
 
        BigDecimal percent = new BigDecimal("0.10");
        BigDecimal discount = price.multiply(percent);
        return price.subtract(discount.setScale(2, RoundingMode.HALF_UP));
    }
}

И служба скидок применяет эту скидку к указанной цене.

01
02
03
04
05
06
07
08
09
10
11
12
13
package com.gkatzioura.solid.ocp;
 
import java.math.BigDecimal;
 
public class DiscountService {
 
    public BigDecimal applyDiscounts(BigDecimal price,Discount discount) {
 
        BigDecimal discountPrice = price.add(BigDecimal.ZERO);
        discountPrice = discount.apply(discountPrice);
        return discountPrice;
    }
}

Однако наша компания хочет предложить скидку пожилым, поэтому у нас есть старшая Скидка.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package com.gkatzioura.solid.ocp;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
 
public class SeniorDiscount {
 
    public BigDecimal apply(BigDecimal price) {
 
        BigDecimal percent = new BigDecimal("0.20");
        BigDecimal discount = price.multiply(percent);
        return price.subtract(discount.setScale(2, RoundingMode.HALF_UP));
    }
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
package com.gkatzioura.solid.ocp;
 
import java.math.BigDecimal;
 
public class DiscountService {
 
    public BigDecimal applyDiscounts(BigDecimal price,Discount discount) {
 
        BigDecimal discountPrice = price.add(BigDecimal.ZERO);
        discountPrice = discount.apply(discountPrice);
        return discountPrice;
    }
 
    public BigDecimal applySeniorDiscount(BigDecimal price,SeniorDiscount discount) {
 
        BigDecimal discountPrice = price.add(BigDecimal.ZERO);
        discountPrice = discount.apply(discountPrice);
        return discountPrice;
    }
 
}

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

Чтобы следовать принципу открытого / закрытого, мы создадим интерфейс скидок.

1
2
3
4
5
6
7
8
package com.gkatzioura.solid.ocp;
 
import java.math.BigDecimal;
 
public interface Discount {
 
    BigDecimal apply(BigDecimal price);
}

Скидка по умолчанию будет переименована в AdultDiscount и реализует интерфейс скидок.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
package com.gkatzioura.solid.ocp;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
 
public class AdultDiscount implements Discount {
 
    @Override
    public BigDecimal apply(BigDecimal price) {
 
        BigDecimal percent = new BigDecimal("0.10");
        BigDecimal discount = price.multiply(percent);
        return price.subtract(discount.setScale(2, RoundingMode.HALF_UP));
    }
}

SeniorDiscount также реализует интерфейс Discount.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
package com.gkatzioura.solid.ocp;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
 
public class SeniorDiscount implements Discount {
 
    @Override
    public BigDecimal apply(BigDecimal price) {
 
        BigDecimal percent = new BigDecimal("0.20");
        BigDecimal discount = price.multiply(percent);
        return price.subtract(discount.setScale(2, RoundingMode.HALF_UP));
    }
}

Наконец, что не менее важно, наш DiscountService будет реорганизован для применения скидок на основе интерфейса Discount.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package com.gkatzioura.solid.ocp;
 
import java.math.BigDecimal;
 
public class DiscountService {
 
    public BigDecimal applyDiscounts(BigDecimal price,Discount[] discounts) {
 
        BigDecimal discountPrice = price.add(BigDecimal.ZERO);
 
        for(Discount discount:discounts) {
 
            discountPrice = discount.apply(discountPrice);
        }
 
        return discountPrice;
    }
}

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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
package com.gkatzioura.solid.ocp;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
 
public abstract class BasicDiscount implements Discount {
 
    @Override
    public BigDecimal apply(BigDecimal price) {
 
        BigDecimal percent = new BigDecimal("0.01");
        BigDecimal discount = price.multiply(percent);
        return price.subtract(discount.setScale(2, RoundingMode.HALF_UP));
    }
}

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

Вы можете найти исходный код на github . Следующий принцип — принцип замещения Лискова .

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

Опубликовано на Java Code Geeks с разрешения Эммануила Гкациоураса, партнера нашей программы JCG. См. Оригинальную статью здесь: Твердые принципы: открытый / закрытый принцип

Мнения, высказанные участниками Java Code Geeks, являются их собственными.