Заменить условный полиморфизм
Я пытаюсь понять эту практику чистого кода с примером. Рассмотрим класс продукта с коробкой переключения для скидки. Я пытаюсь заменить оператор switch на полиморфизм.
Перед кодом:
class Product {
String priceCode;
int discount;
Product(String priceCode) {
setDiscount(priceCode);
}
public int getDiscount() {
return discount;
}
public void setDiscount(String priceCode) {
switch (priceCode) {
case "CODE1":
discount = // some logic;
case "CODE2":
discount = // some other logic;
case "CODE3":
discount = // some other logic;
}
}
}
В приведенном ниже коде, как вы можете видеть, я удалил оператор switch, но у меня все еще есть условия для создания объекта discountStrategy.
Мой вопрос: у меня все еще есть условия, которые я пытаюсь удалить с помощью полиморфизма.
После кода:
class Product {
String priceCode;
DiscountStrategy discountStrategy;
Product(String priceCode) {
setDiscount(priceCode);
}
public int getDiscount() {
return discountStrategy.getDiscount();
}
public void setDiscount(String priceCode) {
if (priceCode.equals("CODE1")) {
discountStrategy = new DiscountStrategy1();
} else if (priceCode.equals("CODE2")) {
discountStrategy = new DiscountStrategy2();
}
// ...
}
}
interface DiscountStrategy {
public int getDiscount();
}
class DiscountStrategy1 implements DiscountStrategy {
public int getDiscount() {
// calculate & return discount;
}
}
class DiscountStrategy2 implements DiscountStrategy {
public int getDiscount() {
// calculate & return discount;
}
}
class DiscountStrategy3 implements DiscountStrategy {
public int getDiscount() {
// calculate & return discount;
}
}
Не могли бы вы помочь мне понять эту концепцию с лучшей реализацией этого примера?
Ответы
Ответ 1
Я думаю, что класс продукта не должен знать о процессе создания скидки, он должен использовать только скидку. Итак, мое предложение состоит в том, чтобы создать скидку factory с Картой, которая будет содержать различные реализации скидок:
class DiscountFactory {
private static final Map<String, DiscountStrategy> strategies = new HashMap<>();
private static final DiscountStrategy DEFAULT_STRATEGY = () -> 0;
static {
strategies.put("code1", () -> 10);
strategies.put("code2", () -> 20);
}
public DiscountStrategy getDiscountStrategy(String priceCode) {
if (!strategies.containsKey(priceCode)) {
return DEFAULT_STRATEGY;
}
return strategies.get(priceCode);
}
}
После этого класс Product можно упростить:
class Product {
private DiscountStrategy discountStrategy;
Product(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
public int getDiscount() {
return discountStrategy.getDiscount();
}
}
Функциональный интерфейс позволит вам создавать различные реализации с использованием лямбда-выражений:
interface DiscountStrategy {
int getDiscount();
}
И, наконец, пример использования продукта вместе со скидкой:
DiscountFactory factory = new DiscountFactory();
Product product = new Product(factory.getDiscountStrategy("code1"));
Ответ 2
Мои два цента:
Вам нужно будет передать параметры методу discount()
.
а. Создайте статический класс HashMap
DiscountStrategy
.
Например:
map.put("CODE1", new DiscountStrategy1());
map.put("CODE2", new DiscountStrategy2());
б. где вам нужно, вы можете просто использовать:
map.get(priceCode).discount()
Ответ 3
Вот что вам нужно сделать
class Product {
String priceCode;
DiscountStrategy discountStrategy;
HashMap<String, DiscountStrategy> map=new HashMap();
Product(String priceCode) {
map.put("CODE1", new DiscountStrategy1());
map.put("CODE2", new DiscountStrategy2());
map.put("CODE3", new DiscountStrategy3());
setDiscount(priceCode);
}
public void setDiscount(String priceCode){
discountStrategy=map.get(priceCode);
}
public int getDiscount() {
return discountStrategy.getDiscount();
}
}
Ответ 4
Когда, как представляется, в вашем примере стратегия скидок привязана к определенному типу продукта, я бы вычислил скидку на уровне позиции заказа.
Например:
class Product {
double basePrice;
DiscountStrategy discountStrategy;
...
public double getBasePrice() {
return basePrice;
}
public DiscountStrategy getDiscountStrategy() {
return discountStrategy;
}
}
interface DiscountStrategy {
public double calculate(int quantity, Product product);
}
class OrderItem {
int quantity;
Product product;
public double getAmount() {
DiscountStrategy ds = product.getDiscountStrategy();
double discount = ds.calculate(quantity, product);
return quantity*(product.getBasePrice() - discount);
}
}
Пример стратегии скидок: скидка за количество:
class QuantityRateDiscount implements DiscountStrategy {
static class QuantityRate {
final int minQuantity;
final double rate; // in %
QuantityRate(int minQuantity, double rate) {
this.minQuantity = minQuantity;
this.rate = rate;
}
}
QuantityRate[] rateTable;
// rateTable must be sorted by ascending minQuantity
QuantityRateDiscount(QuantityRate... rateTable) {
this.rateTable = rateRable.clone();
}
@Override
public double calculate(int quantity, Product product) {
QuantityRate qr = null;
for (QuantityRate qr2: rateTable) {
if (qr2.minQuantity > quantity) {
break;
}
qr = qr2;
}
if (qr != null) {
return product.getBasePrice()*qr.rate/100.0;
} else {
return 0;
}
}
}