web-dev-qa-db-ja.com

条件付きを多態性で置き換える

このクリーンなコードの実践を例を挙げて理解しようとしています。割引のためにスイッチケースを持つクラスの製品を考えてみてください。 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のオブジェクトを作成するif条件があります。私の質問は、ポリモーフィズムで削除しようとしている条件がまだあるかどうかです。

コードの後:

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;
    }
}

この例をより適切に実装して、この概念を理解するのを手伝っていただけませんか?

17
user1298426

Productクラスは割引の作成プロセスを認識してはいけないと思います。割引のみを使用する必要があります。したがって、私の提案は、さまざまな割引の実装を保持するMapを使用して割引ファクトリを作成することです。

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"));
19

私の2セント:パラメータをdiscount()メソッドに渡す必要があります。

a。静的クラスレベル HashMap of DiscountStrategyを作成します。例:

map.put("CODE1", new DiscountStrategy1());
map.put("CODE2", new DiscountStrategy2());

b。必要なところはどこでも、簡単に使用できます。

map.get(priceCode).discount()
4
akshaya pandey

あなたの例でそうであるように、割引戦略が特定の製品タイプにバインドされている場合、注文アイテムレベルで割引を計算します。例えば:

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;
        }
    }
}
0
Maurice Perry

これはあなたがする必要があることです

    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();
    }
}
0
Mars Moon