【问题标题】:Abstract base class implementing derived class interface methods实现派生类接口方法的抽象基类
【发布时间】:2012-03-14 00:46:48
【问题描述】:

我有以下类和接口。我想基本上冻结 IOld 接口(将被弃用)并强制用户使用 INew 接口,该接口将包含与 IOld 相同的方法。然而,INew 方法 Meth3 表示与 IOld Meth2 相同的功能,但返回类型不同,为了更好地区分它们,我认为这种设计是合适的。我的问题是,这被认为是良好的编码实践吗?

注意:IOld 和 INew 位于单独的程序集中。 NewClass 不能以任何方式引用 IOld,因为它将作为可远程 (MarshalByRef) 对象公开,客户端将通过 INew 接口连接到该对象。我不希望新客户端引用 IOld 程序集。

public interface IOld
{
    void Meth1();
    double Meth2(int input);
} 

public interface INew
{
    void Meth1();
    float Meth3(int input);
} 

public abstract class BaseClass
{
    public virtual void Meth1()
    {
    } 

    public virtual double Meth2(int input)
    {
        throw new NotImplementedException();
    } 
} 

public class OldClass
:
    BaseClass,
    IOld
{
    public override double Meth2(int input)
    {
        return 0;
    } 
} 

public class NewClass
:
    BaseClass,
    INew
{
    public float Meth3(int input)
    {
        return 0;
    } 
}

【问题讨论】:

    标签: c# .net interface abstract-class


    【解决方案1】:

    坐下来,用坚实的基础建造金字塔。您设置的方式,抽象基类和接口是实现相同概念的竞争方法。您这样做主要是为了方便旧版与新版的对比,但这样做时会得到一个相当时髦的依赖关系图。

    根据您编写的内容,您唯一的问题是具有相同签名的方法。如果不是因为这个问题,您可以轻松扩展旧界面而不会出现问题。如果该方法在新方法中发生更改,是重构更改(可接受)还是完全不同的结果?换句话说,老客户可以调用新客户吗?如果是这样,也不需要在不同的接口上使用该方法。

    确保您弃用这些方法,以便用户知道他们将失去旧方法。还要确保记录在案。

    【讨论】:

    • 感谢您的意见;不,老客户不能打电话给新客户。我应该指出的一点是,NewClass 不能以任何方式引用 IOld,因为它将作为可远程对象公开,并且通过 INew 接口获取它的客户端无法拉入 IOld 程序集。
    • 你在使用源代码控制吗?有能力分支吗?我问是因为听起来老客户会继续使用旧的,直到代码更新,新的总是会出现新的。如果是这样,您将代码分支并将旧代码保留在维护分支中,将新代码保留在当前分支中。维护分支仅用于错误修复。最后一步是确保您已经考虑了版本控制,并简单地为一个客户端提供 DLL 版本 1 和另一个版本 2。唯一的问题是如果一个客户端在一段时间内同时需要这两个版本。如果不是,那么它只是软件更改的一部分。
    • 不幸的是,除非万不得已,否则我们不能要求客户重新编译他们的代码(这会像往常一样花费他们!),因此我们需要向后兼容 IOld。但是,我们不打算支持 IOld,并且将对 INew 进行任何错误修复,我们会建议他们重新编译。旧客户端将继续使用旧接口/新客户端和新客户端,彼此之间没有任何可见性,除非在服务器上通过 2 个 API 处理来自远程客户端的远程调用。
    • 所以,客户端 A 将更新。他们是否有可能只更新一种方法然后发布,或者他们会完全转移到新界面?如果他们要进行全面转变,那么拥有两个库(版本 1 是旧的,版本 2 是新的)仍然是一种选择。您必须在一个类中同时拥有两个接口的唯一例外是,如果您正在对程序集进行 GAC,即使如此,您也可以发挥一些配置魔术来将旧客户端保持在旧版本上。我并不是建议这是方式,只是如果版本是问题,则有选项。
    • 他们将完全迁移到新的界面组件。附带说明一下,IOld 程序集实际上是 GAC 注册的(还包含一个使用 COMInterop 的 COM 接口),而 INew 程序集(无 COM)不会,但将是强命名的,因此我仍然可以使用发布者策略等来重定向老客户到未来的新版本。
    【解决方案2】:

    我会尝试这样的:

    public class OldClass : BaseClass, IOld
    {
        public override double Meth2(int input)
        {
            return 0.0;
        }
    }
    
    public class NewClass : OldClass, INew // now implements IOld and INew using the Method2() from OldClass
    {
        [Obsolete("This method is deprecated . Use Method3() instead.")]
        public override double Meth2(int input)
        {
            return base.Meth2(input);
        }
        public float Meth3(int input)
        {
            return return 0.0f;
        }
    }
    

    将方法标记为已弃用以通知开发人员他们需要更新其代码,而不是通过终止旧方法来破坏它,这被认为是更好的做法。

    【讨论】:

    • 感谢您的意见;是的,我会将界面标记为已弃用,但想指出基本设计;我应该指出的一点是,NewClass 不能以任何方式引用 IOld,因为它将作为可远程对象公开,并且通过 INew 接口获取它的客户端不能拉入 IOld 程序集。我已经相应地更新了我的问题。
    【解决方案3】:

    我宁愿添加一个名称稍有不同的新方法,而不是创建新接口。

    所以旧界面例如:

    public interface IOld
    {
        void Meth1();
        [Obsolete("Use Meth22 instead.")]
        double Meth2(int input);
        float Meth22(int input);
    } 
    

    【讨论】:

    • 谢谢 - 我在问题的末尾添加了一条注释,这意味着我不会继续使用 IOld 界面。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-11
    • 2020-02-04
    • 2011-11-20
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 2010-09-22
    相关资源
    最近更新 更多