我应该把多个实现同一接口的类所需的通用逻辑放在哪里?

4

考虑以下接口:

public interface IFoo
{
    bool Foo(Person a, Person b);
}

以下是对上述内容的两种实现方式:
public class KungFoo : IFoo
{
    public bool Foo(Person a, Person b)
    {
        if (a.IsAmateur || b.IsAmateur) // common logic
          return true;
        return false;
    }
}

public class KongFoo : IFoo
{
    public bool Foo(Person a, Person b)
    {
        if (a.IsAmateur || b.IsAmateur) // common logic
          return false;
        return true;
    }
}

我应该把“通用逻辑”(在代码中作为注释)放在哪个位置,这样它只存在于一个地方(例如作为Func),不需要为多个实现重复编写(如上例)?
请注意,上面的示例非常简单,但现实生活中的“通用逻辑”更加复杂,而Foo()方法执行了一些有用的操作!
我希望问题已经很清楚(并且没有在其他地方得到答案 - 我确实做了搜索),但如果需要,请随时向我询问更多详细信息。

看起来这里有一个非常相似的问题:http://stackoverflow.com/questions/5343923/where-to-put-common-interface-methods-when-dealing-with-partial-classes-inherit - 在我发布这个问题之后才在相关部分看到它!尽管我的问题是当两个方法做不同的事情但是内嵌有共同逻辑... - Appulus
这里有点不太清楚你具体指的是什么常见逻辑。你指出了一行代码,它根本没有引用类的属性,因此可以将其分解为某个实用程序类中的静态方法。如果您的公共代码使用类成员,则可以使用扩展方法,但前提是这些成员由接口公开。最后,您可以使用基类。但“正确”的答案在某种程度上取决于常见逻辑的具体情况。 - James Gaunt
1
@James:感谢您的评论。很抱歉,我犯了个错误,我的常规逻辑过于简单,但a和b是两种不属于实现类的不同类型/类的对象。因此,基于您的评论,它可能应该放在一个实用程序类中的静态方法中。 - Appulus
如果逻辑没有引用任何成员变量,那么它本质上就是一个静态方法,所以我会把它写成静态方法。如果您喜欢这种设计,仍然可以将其放在公共基类中,但这会限制您从其他基类派生实现接口的能力。因此,我个人会选择一个单独的内部实用程序类。 - James Gaunt
5个回答

9
在一个常见的抽象类中:
public interface IFoo
{
    bool Foo(Person a, Person b);
}

public abstract class FooBase : IFoo
{
    public virtual bool Foo(Person a, Person b)
    {
        if (a.IsAmateur || b.IsAmateur) // common logic
          return true;
        return false;
    }
}

public class KungFoo : FooBase
{

}

public class KongFoo : FooBase
{
    public override bool Foo(Person a, Person b)
    {
        // Some other logic if the common logic doesn't work for you here
    }
}

2
当然这是个人喜好问题,但是在一个类名前加上 'I' 前缀,而这通常被保留给接口,对我来说似乎不太合适。我很喜欢抽象类的思想,但我会去掉 'I'。 - James Gaunt
不叫抽象类IFooBase而是直接叫FooBase不是更好吗? - nawfal
@JamesGaunt:不,你说得完全正确。如果我发现我的初级开发人员这样做,我会踢他们的屁股。我当时在快速打字以便尽快回答。我很快就会在编辑中更改它。 - Joel Etherton
感谢您的建议,@Joel。我现在知道如何实施我的解决方案了。 - Appulus
很抱歉,我还不是完全成熟的用户,所以无法点赞。 - Appulus

1

您可以使用基类来实现常用方法,但是您的通用逻辑(或业务规则)可以使用规范模式进行外部化处理。

有很多冗长的示例和白皮书可供参考,如果您对此类内容感到满意,可以仔细阅读它们(我发现这些内容有点过于学术化),但是在以下链接中也提供了一个很好的介绍:

http://devlicio.us/blogs/jeff_perrin/archive/2006/12/13/the-specification-pattern.aspx


感谢你提供的规范模式信息,Adrian。我正在阅读相关资料。 - Appulus

0
我会像这样使用一个抽象基类:
public interface IFoo
{
    bool Foo(Person a, Person b);
}

public class KungFoo : FooImpl
{
    public override bool Foo(Person a, Person b)
    {
        if (this.IsAmateur(a, b))
            return true;
        return false;
    }
}

public class KongFoo : FooImpl
{
    public override bool Foo(Person a, Person b)
    {
        if (this.IsAmateur(a, b))
            return false;
        return true;
    }
}

public abstract class FooImpl : IFoo
{
    public abstract bool Foo(Person a, Person b);

    protected readonly Func<Person, Person, bool> IsAmateur = (a, b) => a.IsAmateur || b.IsAmateur;
}

public class Person
{
    public bool IsAmateur { get; set; }
}

谢谢你的建议,@Franky,现在我有点头绪了。 - Appulus

0

我不是C#开发人员,但我认为您需要将父类更改为实际的类并在其中实现该方法。当然,如果您想添加其他未实现的方法,您可以声明一个抽象类,但它看起来应该像这样:

public abstract class IFoo{
   bool Foo(Person a, Person b){
      if (a.IsAmateur || b.IsAmateur) // common logic
         return true;
   }
   public abstract Object otherFooMethod(Object o);
}

然后在你的子类中,你会像这样使用它:

public class KungFoo : IFoo{
   //Foo already implemented

   public Object otherFooMethod(Object o){
      return o;
   }

}

public class KongFoo : IFoo
{
   public bool Foo(Person a, Person b)
   {
       if (a.IsAmateur || b.IsAmateur) // common logic
         return false;
       return !base.Foo();
   }

   public Object otherFooMethod(Object o){
      return o;
   }
 }

0
  • 你可以实现一个类,该类被所有适当的类继承,并提供protected方法的功能。

  • 最好你可以实现一个扩展方法,我更喜欢这种方法,因为它不限制你在特定的继承层次结构中使用此逻辑,而是允许你在共享类型或接口的所有类中使用它。


感谢您的建议,@Jens。我应该给出一个更现实的常见逻辑示例(即参数是不同类型),因此实现扩展方法会很困难。 - Appulus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接