如何创建具有可变参数/不同方法签名的方法接口?

Posted

技术标签:

【中文标题】如何创建具有可变参数/不同方法签名的方法接口?【英文标题】:How to create method interface with variable parameters / different method signatures? 【发布时间】:2011-09-01 03:40:55 【问题描述】:

我正在尝试创建一个通用类的接口,但实现类可以有不同的参数。

例如

public interface IViewModel

    //...
    void ResetReferences(); 


// and then, in my class implementations, something like this:
public class LocationViewModel : IViewModel

    public void ResetReferences(List<StateProvinces> stateProvinces) //...


public class ProductViewModel : IViewModel

    public void ResetReferences(List<Color> colors, List<Size> sizes) //...

所以请注意,我想标准化 ResetReferences 命名约定。我很确定我不能这样做,但是有没有可行的设计模式?例如在我的界面中,如下所示?

// variable parameters
void ResetReferences(params object[] list); 

但是我该如何进行类型检查或让它调用我想要的实际方法签名等?

也许接口是错误的使用方式?也许只是一个基类和一些编码约定?

谢谢,

【问题讨论】:

【参考方案1】:

用实现相关接口的对象替换您的 args 列表:

public interface IViewModel

    //...
    void ResetReferences(IResetValues vals); 

我应该补充一点,IMO,ResetReferences() 不应该接受参数......它应该重置为特定于实现您的接口的各个类型的默认值......“重置”是这个词对我来说意味着“恢复到初始状态”...添加 args 意味着您可以控制它。

【讨论】:

我喜欢你的方法,谢谢。顺便说一句,我已将该方法重命名为“SetReferences”:) @Raymond:如果您喜欢这个答案,请点赞,并给 JeffSahol 10 更多声望点。人们欣赏“谢谢”评论,但在追求声誉的过程中,评论无济于事。【参考方案2】:

您必须在接口中同时拥有这两种方法(并且让一个不正确的方法对实例抛出不受支持的异常),或者让接口从其他两个接口继承以达到相同的效果。

接口定义是整个签名。

也可以将对象作为参数传递(可能从 ParameterProvider 基类派生),以便对象封装动态特性并仍然允许接口是静态的。但那一点你基本上是在围绕类型系统工作。

【讨论】:

【参考方案3】:

如果参数可以不同,那么它就不是一个真正的通用接口。这么说吧:调用者需要知道实现类吗?如果是这样,您就失去了接口的松散耦合优势。

一种选择是将参数封装到另一种类型中,并使该类在该类型上通用。例如:

public interface IViewModel<T>

    void ResetReferences(T data);

然后您将List&lt;Color&gt; colors, List&lt;Size&gt; sizes 封装为一种类型,并可能将List&lt;StateProvinces&gt; stateProvinces 放入另一种类型中。

虽然有点尴尬……

【讨论】:

“虽然有点尴尬……” 解决这个问题最理想的方法是什么? @b1nary.atr0phy:理想情况下“不要让自己陷入这种情况”。鉴于信息有限,我已经给出了我能给出的最佳答案——它非常敏感。 我不认为你可以在ResetReferences(T data)的实现中做任何通用的事情,T没有通用的接口可以操作。 @zoujyjs:但实现不必是通用的——它可以特定于一种类型。这不是通用的方法 - 它是接口。所以有人可以实现IViewModel&lt;Foo&gt;,他们只需要知道如何处理 Foo。【参考方案4】:

你需要实现接口方法,但你仍然可以做你想做的事

public class LocationViewModel : IViewModel

    public void ResetReferences(List<StateProvinces> stateProvinces) // ...

    void IViewModel.ResetReferences() // ...

【讨论】:

这不是一个好的解决方案,因为它违反了SOLID原则的接口隔离原则(ISP):一个类不得必须实现特定类不需要的任何接口元素!跨度> 【参考方案5】:

接口的目的是让客户端代码知道接口并忽略实现。如果您的实现在调用时需要特殊处理,则客户端代码需要知道它正在调用什么实现,然后接口的整个目的就丢失了。

除非我完全误解了你想要完成的事情,否则你走错路了。

【讨论】:

是的,我认为你是对的。我把逻辑放在错误的地方。 (这是一个 MVC 应用程序,所以我现在将 ResetReferences 放在 Controller 类而不是 ViewModel 类中)。 完全正确。在实现类中隐藏功能会从interface 中带走很多价值,因为interface 并没有完全定义实现类将要做什么。

以上是关于如何创建具有可变参数/不同方法签名的方法接口?的主要内容,如果未能解决你的问题,请参考以下文章

我可以将数组作为参数传递给 Java 中具有可变参数的方法吗?

使用 preg_replace_callback 查找并替换具有可变数量参数的函数签名

如何创建一个接受可变数量参数的 Java 方法?

具有不同编译器的 C++ 和可变参数

java中set接口哈希表哈希值HashSetLinkedHashSet方法的可变参数

java中set接口哈希表哈希值HashSetLinkedHashSet方法的可变参数