Helper类(es)vs功能继承。最佳实践

时间:2010-06-17 19:29:25

标签: language-agnostic inheritance

我有一些实现ICommand {Execute}接口的命令类。有几个命令有重复的代码片段。我有几种选择如何干:

  • 创建静态帮助程序类并在其中移动重复代码
  • 使用受保护的帮助程序方法创建命令继承

你会建议什么以及为什么?

ADDED 谢谢大家的回复,很多答案都很相似而且很有用!

8 个答案:

答案 0 :(得分:5)

而不是静态类,另一个选择是将公共代码放在一个新类中,并使用依赖注入将helper类注入到命令中。这也与继承概念的构成有关。

答案 1 :(得分:3)

如果层次结构外的其他类可能还需要重复逻辑,我会把它放到静态帮助器类中。否则在具有受保护继承的基类中。

答案 2 :(得分:3)

在我看来,如果它只与该类层次结构相关并且不会在它之外使用,我会将重复的代码放入基类中。如果有可能在不同的类中使用代码,则将其移动到公共项目中的辅助类。

享受!

答案 3 :(得分:3)

这完全取决于重复代码的性质。

助手功能的输入/输出是什么?它们是否在逻辑相关的变量集上运行?然后 - 是的,你最好创建一个基类,将这些变量作为成员,以及相关的辅助函数集。

否则,如果辅助函数中的参数不一致,那么无论如何都要将这些函数实现为静态函数,对吧?在这种情况下,我没有看到使继承复杂化的原因,我只使用辅助函数(或者,如果您的语言不将函数视为一等公民,则使用静态帮助程序类)。

答案 4 :(得分:1)

这里可能没有正确/错误的答案,但我想你肯定可以很好地实现它。它可能非常依赖于您的实际要求以及您的命令彼此之间的关系。通常,我可能会使用基类实现和继承层次结构,假设命令是相关的,并且代码直接与命令本身相关,而不是与某些本身应该是类的外部实体相关。当然,它们与命令有关,基类可以反映出来。

如果你的代码只对不相关命令的子集是通用的,那么创建一个继承层次结构会强制一个不存在的关系,然后添加一个“helper”类(如果可能的话,是非静态的) ,以提高可测试性)将是解决该问题的一种非常自然的方式。您可能会发现可以将“帮助器”方法自然地分组到自己的类中。例如,如果有几种方法需要与您的身份验证子系统进行交互,那么您可能拥有这些方法的AuthenticationMediator。我也没有看到与两者兼顾的任何冲突。

答案 5 :(得分:1)

在自己的代码中使用帮助程序是一种糟糕的做法,它来自于懒惰。

您真正需要帮助的唯一可能情况是扩展密封类的行为,如硒等第三方库。

什么是帮手?它是一种静态方法,它位于一些类本身。

我们遇到了什么问题?

  1. 静态方法。单元测试有问题。例如,我们的开发人员向助手添加了缓存。因此,没有可能只是简单地模拟这些方法,而我必须添加到许多逻辑只是为了简单的模拟。是的,有可能错误地使用静态方法...但是在开始时没有人希望将状态添加到帮助程序。
  2. 位置。方法位于另一个类中,远离基本逻辑。这是一个错误的代码设计概念。
  3. 何时使用助手?当您需要更换第三方库时,无法继承它。否则只需继承lib。

    什么时候不使用帮手?减少重复的代码。您需要将此代码移动到另一个服务。了解DDD以提高重构技能,并了解如何以最佳方式管理服务

答案 6 :(得分:0)

如果逻辑在接口成员上运行,而不是实现成员,则建议编写辅助方法[或扩展方法]。

public IRandom
{
    byte NextByte ();
}

public static class IRandomExtensions
{
    // logic that acts against public interface IRandom
    // may be applied to all implementations
    public static int GetNextUnbiasedInteger (this IRandom random) { }
    public static IEnumerable<T> Shuffle<T> (
        this IRandom random, 
        IEnumerable<T> items) { }
}

如果业务逻辑针对实现成员进行操作,

public class SomeCommand : ICommand
{
    // an implementation-specific member, NOT a member
    // of ICommand
    public int SomeControlCount { get; set; }
}

// a method that references implementation-speciic
// details. where should this go?
public void DoSomething ()
{
    SomeCommand command;
    int count = command.SomeControlCount;
}

那么我们可能应该将它更紧密地绑定到实现类。如果这是一个常见的事件,那么基类可能是有意义的。

就个人而言,复杂的层次结构比它们的价值更麻烦,在可维护性,易读性和重用性方面使用自己的判断,你应该没问题!

希望这有帮助! :)

答案 7 :(得分:0)

无状态代码使用助手。

具有多个方法的状态依赖代码使用继承。例如,当多个方法使用共享成员变量并因此维持共享状态时。

目标是减少重复代码的数量,这取决于它是什么类型的代码。然而,当人们过度使用这个并制作超级抽象类或辅助函数时,我真的很讨厌,这些函数可以跳转到其他扼杀抽象代码,这些代码的名称类似于&#34; Executor&#34; &#34;祈求&#34; &#34; DataConveyer&#34; &#34;的DataManager&#34; &#34; SharedCode&#34 ;.并且在所有这些跳转的最后,实际上设法完成了它应该做的工作,但是彼此之间是如此互联,以至于你不确定在哪里进行新的更改以添加这个新功能。我应该使用DataConveyer还是应该在DataManager中执行此操作?

所以黄金目标应该是,保持简单。