【问题标题】:Is it bad practice for a class to have only static fields and methods?一个类只有静态字段和方法是不好的做法吗?
【发布时间】:2010-12-28 21:53:33
【问题描述】:

我有一个类,它由静态成员变量和静态方法组成。本质上,它是一个通用的实用程序类。

类只包含静态成员变量和静态方法是不好的做法吗?

【问题讨论】:

  • java.lang.Math 是 100% 静态方法,带有 private 构造函数(无法实例化)。
  • 不确定这个问题是否已在此论坛中提出。但是一个类只有静态字段是不是一种不好的做法?我见过很多这样的课程,我认为它们不适合 OOP。
  • @ka3ak 仅具有静态字段的类在此问题的一些答案中得到了部分解决。

标签: oop class static


【解决方案1】:

不,我不这么认为。让一个类充满实例方法实际上并不依赖于特定实例是更糟糕的做法。将它们设为静态会告诉用户它们打算如何使用。此外,您可以通过这种方式避免不必要的实例化。

编辑:作为事后的想法,总的来说,我认为避免使用语言特性“只是因为”或者因为您认为这是“Java 的做法”是很好的。我记得我的第一份工作,我有一个充满静态实用方法的类,一位高级程序员告诉我,通过使我的所有方法“全局”,我没有完全利用 Java 的 OO 功能。 6 个月后她不在团队中。

【讨论】:

    【解决方案2】:

    只要类没有内部状态并且本质上是所谓的叶类(实用程序类属于此类),换句话说,它独立于其他类。没关系。

    Math 类就是一个很好的例子。

    【讨论】:

    • 你有关于叶子/实用程序类的不错的链接/文章吗?
    【解决方案3】:

    听起来很合理。

    注意:这样做的类通常有一个私有的无参数构造函数,以便在程序员尝试创建静态类的实例时编译器产生错误。

    【讨论】:

    • 私有默认构造函数还可以防止子类化您的静态类。
    • 您是否有任何理由要对静态类进行子类化? (想不出一个……我不是语言大师)
    • 在这种情况下防止子分类是“专业人士”。从事您项目的其他人可能会不小心尝试对您的静态类进行子类化(通过拼写错误或误解)。通过添加私有默认构造函数,您可以通过更严格地执行它的使用方式来为您的类添加更多意义。
    • 将类设为 final 也会阻止子类化。
    【解决方案4】:

    静态方法并不让我担心(测试除外)。

    一般来说,静态成员是一个问题。例如,如果您的应用程序是集群的怎么办?启动时间怎么样——正在发生什么样的初始化?要考虑这些问题以及更多问题,请查看 Gilad Bracha 的 this article

    【讨论】:

    • +1 用于区分静态函数(精细)和静态(可疑)
    【解决方案5】:

    这是完全合理的。事实上,在 C# 中,您可以专门为此目的使用 static 关键字定义一个类。

    【讨论】:

      【解决方案6】:

      只是不要被它冲昏了头脑。请注意,java.lang.Math 类仅与数学函数有关。例如,您可能还有一个 StringUtilities 类,其中包含标准 API 中没有的常见字符串处理函数。但是,如果您的类名为 Utilities,例如,这暗示您可能希望将其拆分。

      【讨论】:

        【解决方案7】:

        另请注意,Java 专门引入了静态导入:(http://en.wikipedia.org/wiki/Static_import)

        静态导入是引入的功能 在 Java 编程语言中 定义的成员(字段和方法) 在一个类中作为公共静态使用 在 Java 代码中不指定 定义字段的类。 该功能被引入 5.0 版中的语言。

        该功能提供了类型安全 包含常量的机制 无需参考代码 最初定义的类 场地。它还有助于弃用 创建常数的练习 接口:一个接口,只有 定义常量然后编写一个类 实现该接口,即 被认为是不恰当的使用 接口[1]。

        机制可以参考 班级的个别成员:

         import static java.lang.Math.PI;
         import static java.lang.Math.pow;
        

        或类的所有静态成员:

         import static java.lang.Math.*;
        

        【讨论】:

        • 我认为这对于他的要求来说有点离题。静态导入与一个类是否只有静态成员无关;如果有的话,它可以工作。
        • 很好的信息和很好的论据说明为什么这是我们应该做的事情。
        • 抱歉,我不同意 - 我认为它是拥有静态方法的论据,但它并没有说明拥有不打算实例化的类。
        • @danben:静态导入对您要实例化的类没有多大意义(至少对我而言)。它对包含大量静态方法(如 java.lang.Math)的“实用程序类”最有意义。你不这么认为吗?
        • 这里可能会吹毛求疵,但我同意你的观点,因为你说它们对你要实例化的类没有多大意义;但是,我不同意它们对无法实例化的类更有意义。
        【解决方案8】:

        虽然我同意这听起来像是一个合理的解决方案的观点(正如其他人已经说过的那样),但您可能需要考虑的一件事是,从设计的角度来看,为什么您有一个仅用于“实用”目的的类.这些功能是否真正在整个系统中通用,或者它们是否真的与您架构中的某些特定类别的对象相关。

        只要您考虑到这一点,我认为您的解决方案没有问题。

        【讨论】:

          【解决方案9】:

          Java SDK 中的Collections 类只有静态成员。

          所以,只要你有适当的理由,你就可以了——这不是一个糟糕的设计

          【讨论】:

            【解决方案10】:

            实用方法通常放在只有静态方法的类中(例如StringUtils。)全局常量也放在它们自己的类中,以便其余代码可以导入它们(public final static 属性。)

            这两种用法都很常见,并且有私有的默认构造函数来防止它们被实例化。声明类 final 可以防止尝试覆盖静态方法的错误。

            如果static member variables 不是指全局常量,您可能希望将访问这些变量的方法放在它们自己的类中。 在这种情况下,您能否详细说明这些变量在您的代码中的作用?

            【讨论】:

              【解决方案11】:

              这通常是实用程序类的设计方式,这并没有错。著名的例子包括o.a.c.l.StringUtilso.a.c.d.DbUtilso.s.w.b.ServletRequestUtils等。

              【讨论】:

                【解决方案12】:

                根据对面向对象设计的严格解释,应避免使用实用程序类。

                问题在于,如果您遵循严格的解释,那么您需要将您的类强制转换为某种对象才能完成许多事情。

                即使是 Java 设计人员也制作实用程序类(想到 java.lang.Math)

                您的选择是:

                double distance = Math.sqrt(x*x + y*y);  //using static utility class
                

                对比:

                RootCalculator mySquareRooter = new SquareRootCalculator();
                mySquareRooter.setValueToRoot(x*x + y*y);
                double distance;
                try{
                   distance = mySquareRooter.getRoot();
                }
                catch InvalidParameterException ......yadda yadda yadda.      
                

                即使我们要避免冗长的方法,我们仍然可以得到:

                Mathemetician myMathD00d = new Mathemetician()
                double distance = myMathD00d.sqrt(...);
                

                在这种情况下,.sqrt() 仍然是静态的,那么首先创建对象有什么意义呢?

                答案是,当您的另一个选择是创建某种对实例变量没有或很少使用的人工“工人”类时,创建实用程序类。

                【讨论】:

                  【解决方案13】:

                  此链接http://java.dzone.com/articles/why-static-bad-and-how-avoid 似乎与此处的大多数答案背道而驰。即使它不包含成员变量(即没有状态),静态类仍然是一个坏主意,因为它不能被模拟或扩展(子类化),所以它违背了 OO 的一些原则

                  【讨论】:

                    【解决方案14】:

                    我不会担心包含静态方法的实用程序类。

                    但是,静态成员本质上是全局数据,应该避免使用。如果它们用于缓存静态方法等的结果,它们可能是可以接受的,但如果它们用作“真实”数据,可能会导致各种问题,例如隐藏的依赖关系和设置测试的困难。

                    【讨论】:

                      【解决方案15】:

                      来自TSLint’s docs

                      来自 Java 风格的 OO 语言的用户可以将他们的实用程序函数包装在一个额外的类中,而不是将它们放在顶层。

                      最好的方法是使用常量,像这样:

                      export const Util = {
                          print (data: string): void {
                              console.log(data)
                          }
                      }
                      

                      此规则的错误代码示例:

                      class EmptyClass {}
                      
                      class ConstructorOnly {
                        constructor() {
                          foo();
                        }
                      }
                      
                      // Use an object instead:
                      class StaticOnly {
                        static version = 42;
                        static hello() {
                          console.log('Hello, world!');
                        }
                      }
                      

                      此规则的正确代码示例:

                      class EmptyClass extends SuperClass {}
                      
                      class ParameterProperties {
                        constructor(public name: string) {}
                      }
                      
                      const StaticOnly = {
                        version: 42,
                        hello() {
                          console.log('Hello, world!');
                        },
                      };
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2011-07-07
                        • 2011-02-14
                        • 2022-01-18
                        • 1970-01-01
                        • 1970-01-01
                        • 2011-09-22
                        • 2011-03-10
                        相关资源
                        最近更新 更多