当前位置:  开发笔记 > Android > 正文

在接口中引用一个实现基类型代码味道?

如何解决《在接口中引用一个实现基类型代码味道?》经验,为你挑选了3个好方法。

我面临的设计决定对我来说没有味道,但让我停下来.看一下下面的代码示例:

public interface IGenerator
{
  ///
  /// Combines two generators; performs magic as well
  /// 
  BaseGenerator Combine(BaseGenerator next);

  ///
  /// Does what a generator does.
  /// 
  object GenerateLolKThx();
}

public abstract class BaseGenerator : IGenerator
{  
  ///
  /// Combines two generators; performs magic as well
  /// 
  public BaseGenerator Combine(BaseGenerator next)
  {
     // do stuff that I really don't want implementors to try and do
     // because its complex and can result in bad juju if done wrong
     return SuperSecretCombine(this, next);
  }

  ///
  /// Does what a generator does.
  /// 
  public abstract object GenerateLolKThx();

  /* other base class methods */
}

我不想详细了解为什么我不想使用Combine方法信任实现者; 足以说它的复杂性.但是,我确实希望尽力强制任何想要实现IGenerator的人扩展BaseGenerator,因为这是正确组合两个生成器的唯一方法.这由接口本身强制执行.

我担心由于我在该界面中引用接口的实现而导致出现意外问题(由"气味"表示).但我也知道这种事情在CS中并不是闻所未闻,它本身也不是坏事(即,描述XSD和用他们编译的语言编写的语言编译器的XML模式).

我感兴趣的原因是为什么这可能是代码气味,这种类型的设计可能导致的陷阱,以及完成我想要的替代设计(确保我的Combine实现用于组合任何和所有类型的生成器).TIA.



1> Rafał Dowgir..:

我很感兴趣为什么这可能是代码味道

这是我的答案:将接口与实现分离的目的之一(甚至可能是主要目的之一)是为接口创建许多不同的实现.将接口绑定到特定的实现类会破坏这一点.

您实际上是说- "此接口必须由BaseGenerator或它的子类实现",但为什么分开IGeneratorBaseGenerator



2> Marc Gravell..:

可以用扩展方法来完成吗?然后你可以使用界面.扩展方法是向接口添加通用实现逻辑的好方法.

这最适合你主要讨论IGenerator(不是具体的类型) - 因为扩展解析更喜欢类型 - 即FredsGenerator可以声明一个定制的Combine方法,如果你输入变量,则会FredsGenerator优先选择.但这与您的示例没有什么不同,因为FredsGenerator可以重新实现接口,窃取实现:

using System;
interface IFoo {
    void Bar();
}
abstract class FooBase {
    public void Bar() { Console.WriteLine("Non-virtual; you can't override me!!!"); }
}
class FooImpl : FooBase, IFoo {
    new public void Bar() { Console.WriteLine("mwahahahahah"); }
}
static class Program {
    static void Main() {
        IFoo foo = new FooImpl();
        foo.Bar();
    }
}

至少使用扩展方法方法,您的代码不能被愚弄为运行重新实现的版本; 您的代码只知道IGenerator,所以使用Generator.Combine版本.永远.


示例(编辑从您的示例中重新编写):

using System;
public interface IGenerator
{
    // note: no Combine
    object GenerateLolKThx();
}

public static class Generator
{
    ///
    /// Combines two generators; performs magic as well
    /// 
    public static IGenerator Combine(this IGenerator current, IGenerator next)
    {
        // do stuff that I really don't want implementors to try and do
        // because its complex and can result in bad juju if done wrong
        Console.WriteLine("Super secret logic here...");
        // and prove we have access the the objects...
        Console.WriteLine(current.GenerateLolKThx());
        Console.WriteLine(next.GenerateLolKThx());
        return next; // just for illustration
    }
}
class MyGenerator : IGenerator
{
    private readonly object state;
    public MyGenerator(object state) {this.state = state;}
    public object GenerateLolKThx() { return state; }
}
public static class Program
{
    static void Main()
    {
        IGenerator foo = new MyGenerator("Hello"),
             bar = new MyGenerator("world");

        IGenerator combined = foo.Combine(bar);
    }
}



3> Rob Prouse..:

根据您显示的有限代码,我认为您正在使用接口只是为了它,抽象基类更合适.如果你不相信任何其他人合并BaseGenerators,那么它应该是你的层次结构的基础,而且Combine不应该是虚拟的,所以没有人可以覆盖它.

推荐阅读
谢谢巷议
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有