design-patterns - 使用接口(interface)然后检查实现类型是否不好?

标签 design-patterns architecture implementation abstraction

考虑以下场景:

我想设计一个折扣计算器,计算出可应用于订单的折扣。有两种类型的订单:在线和店内。根据订单类型和订单总金额,折扣计算器计算折扣。

我用 C# 编程来演示该场景,但问题与语言无关。在下面的代码中,DiscountCalculator 类通过检查输入参数的实际类型来计算折扣。

我觉得在 GetDiscount 方法中检查 IOrder 参数的实际类型是代码味道;因为我隐藏了接口(interface) IOrder 后面的实现细节,所以我以某种方式开箱即用了本应隐藏的内容。

    interface IOrder
    {
        int GetTotalPrice();
    }

    class InStoreOrder : IOrder
    {
        public int GetTotalPrice() { // returns the price of order }
    }

    class OnlineOrder : IOrder
    {
        public int GetTotalPrice() { // returns the price of order }
    }

    class DiscountCalculator
    {
        public int GetDiscount(IOrder order)
        {
            Type orderType = order.GetType();
            if (orderType == typeof(OnlineOrder))
            {
                if (order.GetTotalPrice() < 100)
                    return 2;
                else
                    return 5;
            }
            if (orderType == typeof(InStoreOrder))
            {
                if (order.GetTotalPrice() < 100)
                    return 3;
                else
                    return 6;
            }
            else
                throw new Exception("Unknown order type:" + orderType.Name);
        }
    }

有什么想法吗?

更新:

我真的很感谢大家在这方面的合作。所有的解决方案不仅具有启发性,而且还带来了一种优雅的方式。

顺便说一句,既然所有的答案都让我确信这个解决方案不好,我就在想 Abstract Factory 可能是一个不错的选择。为什么?因为我们正在处理一系列相关对象:OrderDiscountCalculator

像这样:

Factory f = new FactoryRepo ("Online");
IOrder order = f.CreateItem();
IDiscountCalculator discounter = f.CreateDiscountCalculator();
....

这样,我认为对于 future 的变化,正如@Dhruv Rai Puri 指出的那样,可以轻松应用装饰器模式。

有什么想法吗?

最佳答案

是的,检查输入参数的实际类型违背了使用接口(interface)的目的。更好的方法是像这样修改 IOrder 接口(interface)

interface IOrder
{
   int GetTotalPrice();
   int GetDiscount();
}

然后允许每个实现计算适当的折扣。完成此操作后,您可以将 DiscountCalculator 中的方法简化为

order.GetDiscount();

关于design-patterns - 使用接口(interface)然后检查实现类型是否不好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32782193/

相关文章:

c# - .net 默认事件处理程序

mysql - 配置数据 - JSON 存储在表中与单个字段中

c++ - 精心设计的应用程序的开源示例

javascript - Node 代理服务器,瓶颈?

c++ - 我们如何在 C++ 实现文件中包含结构?

java - 实现嵌入在接口(interface)中的类

java - Trove 库队列实现

C++:组织程序子系统的正确方法是什么?

c# - C# 中抽象工厂设计模式的真实世界示例

model-view-controller - 观察者、发布/订阅和数据绑定(bind)之间的区别