【问题标题】:Should a class ever have static and non-static members一个类是否应该有静态和非静态成员
【发布时间】:2010-01-30 19:06:41
【问题描述】:

我试图弄清楚什么时候一个类同时具有静态和非静态函数是合适的。又名:

$obj = new ClassA;
$obj->doOOPStuff();

$something = ClassA::doStaticStuff();

注意:这个例子是用 PHP 完成的,但是问题是语言不可知的。

似乎如果您有一个要实例化的类,那么任何可以静态调用的函数很可能属于另一个类。

在任何可行的情况下,我会有一个使用静态和非静态成员的类吗?

【问题讨论】:

  • 这是我见过的一种模式:class Frob { void tweak() {...} static void tweakIfNotNull(Frob f) { if (f != null) f.tweak(); } } 当方法需要递归地应用于大数据树中的每个节点时,这主要是方便的。像 serialize()dispose()。每个类对其子类使用 ifNotNull 版本。
  • 我见过的另一种模式是静态方法基本上是类其余部分的外观。 en.wikipedia.org/wiki/Facade_pattern
  • “静态”的概念与语言无关,它只针对少数几种语言,即使在这组语言中,最佳实践也各不相同。

标签: language-agnostic oop


【解决方案1】:

一个例子:当创造必须以特定方式发生时。

class Foo {
public:
  static Foo* Create(...params...);

private:
  Foo();
};

【讨论】:

  • +1:这是我多次使用的使用模式。我发现将复杂的创建过程作为自己的方法而不是重载构造函数更清晰(例如c = C::fromXml(xmldoc) 而不是c = new C(xmldoc))。
  • 在这种情况下你可以使用工厂
  • 这种模式称为工厂方法。我发现它在 Objective-C 框架中被大量使用,尽管工厂方法应该只用于方便的构造函数恕我直言。
【解决方案2】:

考虑 .NET 中的 String 类。它包含一个非静态 Split 方法,该方法将一些实例分解为一个 string[] 和一个静态 Join 方法,该方法接受一个 string[] 并再次将其转换为字符串。

当您不需要保持任何状态时,可以使用静态方法。所以Math.Sin() 只取决于它的参数,并且给定相同的参数,输出将始终相同。一个非静态方法可以有不同的行为被多次调用,因为它可以保持一个内部状态。

【讨论】:

    【解决方案3】:

    如果静态方法提供的功能与该类及其对象相关,为什么不呢。这很常见。

    【讨论】:

      【解决方案4】:
      • 静态方法通常是工厂方法

        public class MyClass {    
            public static MyClass createMyClass(int a, double b) {..}
            public static MyClass createSubclassOfMyClass(int c, boolean cond) {..}
            public int calculateThis();
            public double calculateThat();
        }
        
      • 另一个用途是访问在逻辑上绑定到该类的某些属性,但不单独绑定到实例。例如 - 一个缓存:

      (注意——在这个例子中当然要考虑同步)

      public class MyClass {
          public static final Cache cache = new Cache();
          public static void putInCacheIfNeeded(Object obj) {..}
          public static void replaceInCache(Object obj) {..}
      
          public void doSomethingCacheDependend(Object obj) {
              if (something) {
                   MyClass.putInCacheIfNeeded(obj);
              } else {
                   MyClass.replaceInCache(obj);
              }
          }
      }
      

      (示例的 Java 语言)

      【讨论】:

      • +1,如果您还想添加私有的、无状态的实用程序函数,那么完美的答案。
      【解决方案5】:

      想象一下你的构造函数有两个重载都是字符串:

      public class XmlDocument
      {
          public static XmlDocument CreateFromFile(string filePath);
          public static XmlDocument CreateFromXml(string xml);
      }
      

      【讨论】:

      • 这不需要静态方法。例如,您可以为每个类创建一个类,或包含另一个参数。不过,它是有效的。
      • 是的,从技术上讲,您可以检测传入的字符串是否是有效的文件路径,如果是则从文件加载。
      • 你为什么想要两节课?你真的想要这样的构造函数吗? public XmlDocument(string filePath, string xml)
      • @Chacha - 这看起来像 JavaScript 吗? :)
      • @Chaos 什么?只有 Javascript 才能获得自动检测参数的乐趣? :)
      【解决方案6】:

      静态函数可以为构造函数提供有意义的名称。

      $dialog = DialogFoo::createOpenDialog();
      $dialog = DialogFoo::createDocumentOpenDialog();
      $dialog = DialogFoo::createImageOpenDialog();
      

      它也可以用来强制执行Singleton 模式。

      $dialog = DialogFoo::getInstance()
      

      【讨论】:

        【解决方案7】:

        静态类成员在一切必须要么在对象中要么在全局范围内时最有用;它们在支持模块级范围的语言(如 Python)中不太有用。

        【讨论】:

          【解决方案8】:

          当我不想授予对构造函数的访问权限时,我使用静态方法来实例化新对象。我确保在创建和对象之前对类执行任何必要的先决条件。在这个例子中,我有一个计数器来返回创建了多少对象,如果我有 10 个对象,我会阻止实例化更多对象。

          class foo {
          private:
          static int count;
          foo() {}
          
          public:
          static foo bar() {
          count++;
          if (count<=10){
          return new foo;
          } else {
          return null;
          }
          

          【讨论】:

            【解决方案9】:

            假设一个类有实例方法,这里也有一些很好的使用静态方法的例子:

            对于静态实用方法

            此类方法适用于任何实例,例如 Java 中的 String.format(String, Object...)

            当您不想为作业创建特定实例时使用它们。

            对于静态工厂方法

            工厂方法是简单地实例化对象的方法,例如 Java API 中的 getInstance()valueOf() 方法。 getInstance() 是单例中的常规实例化方法,而 valueOf() 通常是类型转换方法,例如 String.valueOf(int)

            在基于接口的框架(如 Java 中的 Collections Framework)中使用它们通过对象缓存提高性能,您可能希望在其中返回子类型,以实现单例(咳)。

            【讨论】:

              【解决方案10】:

              一般来说,静态函数会产生与类本身高度相关的功能。可能是一些辅助函数,工厂方法等。在这种情况下,所有功能都包含在一个地方,它对应DRY原则,增加cohesion,减少coupling

              【讨论】:

                猜你喜欢
                • 2012-04-13
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-08-25
                • 2012-01-21
                • 2011-11-29
                • 1970-01-01
                • 2012-10-20
                相关资源
                最近更新 更多