【问题标题】:Is it good practice in Java OOP to allow an object to know about other instances of its type?Java OOP 中允许对象了解其类型的其他实例是一种好的做法吗?
【发布时间】:2015-08-17 19:15:34
【问题描述】:

我说的特别是关于使用静态变量来实现这一点。考虑 Java 中的以下对象:

public class MyObject{
    private static ArrayList<String> ID_List = new List<String>();
    private String ID_Number;
    public MyObject(){
        /* Assign a random number to ID_Number
         * And ensure that this is a unique number
         * not found in ID_List. Then add it to ID_List. */
    }

    /* Other methods and such */
}

在某种程度上,这是为了确保制作的每个对象都具有易于访问和阅读的独特且可区分的属性。但是,我不确定同一类型的所有对象之间的这种奇怪的耦合是否是好的做法。

由于这让我感到不舒服,我倾向于认为这不是一个好主意。以 OOP 方式思考这个问题的正确方法是什么?

【问题讨论】:

  • 你将如何处理对象deletion?它的 ID 会从列表中删除吗?
  • ArrayList 的内容会在多个对象的创建过程中持续存在,还是每个新对象都会带来一个新的(和空的)ID_List?
  • 我认为你需要一个对象映射,每个对象都有一个唯一的键
  • MyObject 本身在没有唯一 ID 的情况下能否正常工作?也就是这个ID只有MyObjects的人用吗?
  • 您可以考虑使用UUID。 (这使用了足够多的位,以至于发生碰撞的概率低得离谱,不值得担心。)

标签: java oop


【解决方案1】:

使用静态 ID_INCREMENTOR 和本地 objectID 不是很实用吗?在构造函数中,将 ID_INCREMENTOR 加一,然后将 objectID 设置为 ID_INCREMENTOR 当前值?

那么没有两个对象会有相同的 id。

例子:

public class MyObject{
    private static long ID_INCREMENTOR = 0;
    private long id;
    public MyObject(){

          ID_INCREMENTOR++;
          id = ID_INCREMENTOR;

    }

public long getID(){
    return id;
}

/* Other methods and such */
}

据我所知,这可能是最简单的方法。对象不知道彼此,尽管您可以确信没有两个对象将具有相同的唯一标识符,除非您通过类/反射设置它。

【讨论】:

  • 这适用于我的实现!伟大而简单,谢谢!但是,我不得不问这是否是一种已知的设计模式?
  • 我不知道这是什么设计模式的名称——如果它甚至是一种设计模式! :) 如果您绝对需要一个“设计模式名称”,我唯一能想到的就是复合设计模式,这更像是您最初的问题。我将其称为 Singlet 设计模式,因为它解决了相同的问题,但不承认“下属”或同一类的其他实例。该类型是单例模式和复合模式之间的交叉。 tutorialspoint.com/design_pattern 是的,我同意 Long,MaxZoom。 +1 并编辑。 :)
  • 如果这应该是线程保存,您应该使用 AtomicLong 作为 ID_INCREMENTOR 并调用 incrementAndGet() 以获取构造函数中 id 的 long 值。
【解决方案2】:

当你有那个 object.hashcode() 几乎总是为它返回一个唯一的对象 ID 时,为什么要这样做呢?尽管 equals() 和 hashcode() 之间的约定在对象不相等时不强制保证不同的哈希码,但同一对象的不同实例不太可能具有相同的哈希码。此外,我仍然不喜欢在类本身中为该类维护静态 ArrayList 以进行内务处理的方式。即使你需要这样的东西,也要从这个类中外部化那个 ArrayList。让这个对象的唯一实例的管理由不同的类来完成。记住 OOP 的 SOLID 原则中的单一职责原则。

【讨论】:

    【解决方案3】:

    这并不奇怪。您可以在 Effective Java 中找到类似的模式。这是其中的一些信息http://www.informit.com/articles/article.aspx?p=1216151

    正如它所暗示的,我可能会使用工厂方法来获取这些对象,而不是每次都newing 它们。

    【讨论】:

      【解决方案4】:

      这取决于您需要它。

      实际上,Java 提供了一个与 hashCode() 方法类似的机制,它为对象的每个实例返回一个哈希码值(它可能每个类都是唯一的,但这不是强制性的,你有责任正确计算),尽管没有人跟踪该 ID。

      您提到的内容是完全可能的,并且根据您的需要可能是合法的,在其他一些情况下可能完全没有必要,甚至可能导致内存泄漏。

      如果您想保留已创建对象的列表,您可能还需要一个“构建器”类来维护该列表。

      class MyObject {
           private static AtomicInteger count = new AtomicInteger();
           private int id;
           MyObject(){
               id = count.getAndIncrement();
           }
           public int hashCode() {
               return id;
           }
           public void equals(Object o) {
              return o instenceof MyObject && ((MyObject)o).id == this.id;
           }
      }
      class MyObjectBuilder {
          private static List<MyObject> instances = new ArrayList<>();
          public static MyObject createObject() {
               MyObject newOne = new MyObject();
               instances.add(newOne);
               return newOne;
           }
       }
      

      其他选项是使用地图或集合,但同样取决于您的需要。

      您还可以在here 中阅读有关等于和哈希码的更多信息

      【讨论】:

      【解决方案5】:

      我在这里发布我自己的解决方案想法,以防有人看到这个可能会认为我的方法更适合他们的需求。不过,我会接受 PsyChrom 的回答,因为我相信它是最好的。

      假设对象需要时刻知道自己的ID号,并且可能时不时知道内存中其他对象的ID号是多少,考虑如下实现:

      public class MyObject{
          private String ID_Number;
          public MyObject(String ID){
              this.ID_Number = ID;
          }
      
          public getID(){
              return ID_Number;
          }
      
          public checkUniques(List<String> ID_List){
              /* Do what not */
          }
          /* Other methods and such */
      }
      

      假设您只有一个区域正在生成这些对象,那么只需执行以下操作:

      ArrayList<String> ID_List = new List<String>();
      /* Create a number/string before you make the object
       * Which is unique. */
      MyObject newObj = new MyObject(someUniqueStr);
      

      在我自己的实现中,我实际上只需要对象知道自己类型的对象的 ID 号很少。因此,也许只是为它添加一个方法可能会令人满意,而不是为他们提供自己的列表。通过这种方式,我们可以像用户之前建议的那样将我们的对象的内务处理外部化!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-29
        • 2011-06-16
        • 2015-05-30
        相关资源
        最近更新 更多