这对于公共界面来说是更好的设计:
WriteValue(DeviceValueType.MachineName,"micks machine");
OR
WriteMachineName("Micks machine");
如果您使用类型1,那么您只需要一个这样的通用接口,只需向枚举中添加项目即可写入任意数量的 DeviceValueTypes 。
第二种类型更具体,因为它只会将值写入由其方法名称表示的特定类型。但这些方法在类型安全方面具有很大的优势。
例如:让我们考虑另一种类型
WriteValue(DeviceValueType.SleepDelay,"25");
和
WriteSleepDelay(25);
请注意,在这里,类型2有一个优点,因为我可以指定预期的类型。如果我使用类型1,那么我将必须将值转换为int,然后如果该值不在预期范围内则抛出异常。如果我必须通过复杂的类型,这就变得更加困难。
总结如下:
类型1:通用。界面只需要暴露一个方法。参数没有类型安全性。 类型2:具体。界面将需要与类型一样多的方法。输入安全。
解决此问题的一般建议方法是什么?
我正在使用C#,但我认为这个问题是非语言特定的。
答案 0 :(得分:1)
你应该避免使用你所谓的类型1接口。从经验来看,这种界面往往会很快变得混乱。以睡眠延迟为例。你打算如何键入检查该字符串的正整数?你最终会得到一个巨大的开关声明。所以至少要封装它。
尽管你的类型2更好,但应该注意它将写操作与写操作所需的数据紧密耦合。我不知道你要处理的要求(写一次多读?),但你的DeviceValueType枚举表明你可以简单地声明一个具有machine name
和sleep delay
等属性的DeviceConfig类,并将其传递给将执行实际工作的Device或DeviceWriter类。但是,如果machine name
是配置,而sleep delay
实际上是一种方法,您应该考虑将这两个问题分开(即Device.sleep()和Device.writeConfig(DeviceConfig))。
答案 1 :(得分:0)
我来自Python背景,但实际上我会选择这两个选项。制作WriteValue函数,让它完成所有繁重的工作。然后,将WriteMachineName和WriteSleepDelay函数写为WriteValue的简单包装器。这样,您就可以将速记函数用于经常使用的所有函数,并将长版本用于经常未调用的所有函数。
您可能希望在文档中明确地使用它的方式,因此在您知道如何以及为什么这样做之后,他们将不得不使用它。
另外:我不知道C#中的函数调用有多昂贵。如果它们非常昂贵(在CPU时间内),您可能希望始终使用类型1。
答案 2 :(得分:0)
取决于:)
此外,第三种可能性是两种方式:使用正确的参数,使用通用WriteValue()
和特定的'WriteSleepDelay()which in turn calls
WriteValue()`。如果这些方法的实现相当复杂,即如果你有很多冗余代码,除非你将它集中到泛型方法中,这是有意义的。
对于像WriteValue
这样的(大概)简单的事情,为了简单起见,我会采用不同的方法。
更新:对于继承层次结构,在基本接口中使用泛型方法是有意义的。然后,派生类可以添加其他类型安全的方法(例如WriteSleepDelay()
),这些方法仅对 。
或者您可能希望在基类中使用WriteValue(Object value)
替换为子类中的适当类型安全变体(例如,子类WriteValue(Integer)
中的SleepTimer
)。很可能这在你的具体情况下没有意义,但对于其他情况,它可能是理想的。
答案 3 :(得分:0)
首先:我不知道一般规则,也不知道那种情况的设计模式,因此我会写下我会做的事情。
如果您不关心参数的类型,请执行此类WriteValue("micks machine");
之类的操作。但是,不要像格式化字符串等那样做任何格式化整数的技巧,只需简单地写下你得到的字符串并让调用者进行翻译。 (输入0)
我永远不会做类似你的类型1.为什么?你提到了一些原因(类型安全)。但也是为了可读性:你最终会做swtiches或if-then-elses。而且,如果您关心干净的代码,您最终也会使用WriteMachineName("Micks machine");
之类的签名编写私有帮助方法(如在类型2中)。
我更喜欢类型2,可能与类型0混合用于简单类型,例如WritePlain("Micks machine"); WriteNumber(3.4);
注意:在类型1和类型2中,您将一些业务代码移动到这些方法。这既不好也不坏,但你必须选择它是否适用于你的情况(连贯性)。相反,类型0将转换逻辑从类型保持到该类中的字符串。