首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >哪种方法是更好的实践-作为实例或静态的助手方法?

哪种方法是更好的实践-作为实例或静态的助手方法?
EN

Software Engineering用户
提问于 2011-10-02 13:40:32
回答 3查看 67.8K关注 0票数 55

这个问题是主观的,但我只是好奇大多数程序员是如何处理这个问题的。下面的示例是伪C#,但这也适用于Java、C++和其他OOP语言。

无论如何,在我的类中编写助手方法时,我倾向于将它们声明为静态的,如果助手方法需要它们,只需传递字段。例如,给定下面的代码,我更喜欢使用方法调用#2。

代码语言:javascript
运行
复制
class Foo
{
  Bar _bar;

  public void DoSomethingWithBar()
  {
    // Method Call #1.
    DoSomethingWithBarImpl();

    // Method Call #2.
    DoSomethingWithBarImpl(_bar);
  }

  private void DoSomethingWithBarImpl()
  {
    _bar.DoSomething();
  }

  private static void DoSomethingWithBarImpl(Bar bar)
  {
    bar.DoSomething();
  }
}

我这么做的原因是,它表明(至少在我看来)助手方法可能对其他对象有副作用--即使没有读取它的实现。我发现我可以快速地摸索使用这种实践的方法,从而帮助我调试一些东西。

在您自己的代码中,您更喜欢做什么?您这样做的原因是什么?

EN

回答 3

Software Engineering用户

回答已采纳

发布于 2011-10-02 14:22:54

这要看情况了。如果您的助手操作的值是原语,那么静态方法是一个不错的选择,正如Péter所指出的。

如果它们很复杂,那么实心应用,更具体地说是SD

示例:

代码语言:javascript
运行
复制
class CookieJar {
      function takeCookies(count:Int):Array<Cookie> { ... }
      function countCookies():Int { ... }
      function ressuplyCookies(cookies:Array<Cookie>
      ... // lot of stuff we don't care about now
}

class CookieFan {
      function getHunger():Float;
      function eatCookies(cookies:Array<Cookie>):Smile { ... }
}

class OurHouse {
      var jake:CookieFan;
      var jane:CookieFan;
      var cookies:CookieJar;
      function makeEveryBodyAsHappyAsPossible():Void {
           //perform a lot of operations on jake, jane and the cookies
      }
      public function cookieTime():Void {
           makeEveryBodyAsHappyAsPossible();
      }
}

这跟你的问题有关。您可以使makeEveryBodyAsHappyAsPossible成为一个静态方法,它将接受必要的参数。另一种选择是:

代码语言:javascript
运行
复制
interface CookieDistributor {
    function distributeCookies(to:Array<CookieFan>):Array<Smile>;
}
class HappynessMaximizingDistributor implements CookieDistributor {
    var jar:CookieJar;
    function distributeCookies(to:Array<CookieFan>):Array<Smile> {
         //put the logic of makeEveryBodyAsHappyAsPossible here
    }
}
//and make a change here
class OurHouse {
      var jake:CookieFan;
      var jane:CookieFan;
      var cookies:CookieDistributor;

      public function cookieTime():Void {
           cookies.distributeCookies([jake, jane]);
      }
}

现在,OurHouse不需要知道cookie分发规则的复杂性。它现在必须是一个对象,它实现了一个规则。实现被抽象成一个对象,对象的唯一责任是应用规则。这个对象可以单独进行测试。OurHouse只需使用对CookieDistributor的模拟即可进行测试。您可以很容易地决定更改cookie分发规则。

但是,要注意不要做得太过了。例如,让一个由30个类组成的复杂系统充当CookieDistributor的实现,其中每个类只完成一个很小的任务,这是没有意义的。我对SRP的解释是,它不仅规定每个类可能只有一个责任,而且还规定一个单独的责任应该由单个类来执行。

对于原语或像原语一样使用的对象(例如,表示空间中的点的对象、矩阵之类的对象),静态助手类有很多意义。如果您有选择,而且确实有意义,那么您可能实际上考虑向表示数据的类中添加一个方法,例如,Point有一个add方法是明智的。再说一次,别做得太过分。

因此,取决于你的问题,有不同的方式来解决它。

票数 24
EN

Software Engineering用户

发布于 2011-10-02 13:45:22

声明实用程序类static的方法是众所周知的成语,因此这类类不需要实例化。遵循这个成语使您的代码更容易理解,这是一件好事。

但是,这种方法有一个严重的限制:这样的方法/类很难被模仿(尽管AFAIK至少对于C#来说是可以实现这一点的模拟框架,但它们并不常见,其中至少有一些是商业的)。因此,如果助手方法具有任何外部依赖项(例如DB),从而使其调用方难以进行单元测试,则最好将其声明为非静态的。这允许依赖注入,从而使方法的调用者更容易进行单元测试。

更新

澄清:上面讨论了实用程序类,这些类只包含低级别的助手方法,并且(通常)不包含状态。有状态的非实用程序类中的助手方法是一个不同的问题;为错误地解释OP而道歉。

在这种情况下,我感觉到一种代码气味:A类的方法主要作用于B类的一个实例,实际上在B类中可能有一个更好的位置,但是如果我决定将它保持在原来的位置,我更喜欢选项1,因为它更简单,更容易阅读。

票数 21
EN

Software Engineering用户

发布于 2011-10-02 14:08:48

在您自己的代码中,您更喜欢做什么?

我更喜欢#1 (this->DoSomethingWithBarImpl();),除非助手方法当然不需要访问实例的数据/实现static t_image OpenDefaultImage()

你这样做的原因是什么?

公共接口和私有实现与成员是分开的。如果我选择#2和#1,我总是有成员和实例可用,那么程序将更难阅读。与许多基于面向对象的实现相比,我倾向于使用大量的封装,而且每个类的成员很少。至于副作用--我同意,通常会有状态验证来扩展依赖项(例如,需要通过的参数)。

#1的阅读、维护简单得多,并具有良好的性能特点。当然,在某些情况下,您可以共享实现:

代码语言:javascript
运行
复制
static void ValidateImage(const t_image& image);
void validateImages() const {
    ValidateImage(this->innerImage());
    ValidateImage(this->outerImage());
}

如果#2是代码库中的一个很好的通用解决方案(例如默认的),我会关心设计的结构:类做的太多了吗?是封装不够,还是重用不够?抽象级别足够高吗?

最后,如果您使用的是支持变异的面向对象语言(例如,const方法),那么#2看起来是多余的。

票数 4
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/111938

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档