Java:实施双向链接对象

时间:2011-09-20 08:01:59

标签: java reference hyperlink unique

我正在用Java设计游戏引擎。

这个引擎的核心存在两个类Asset和Attribute,其中Asset有一个Attributes列表。大多数属性不需要链接回其属性,这意味着属性可以并且经常出现在多个资产的列表中。但是,存在一个名为UniqueAttribute的属性扩展,它是特定于其资产的属性的实现,并使用链接。

  1. 理想情况下,如果我删除其他代码,我的Asset的addAttribute方法看起来就像这样:

    public void addAttribute(Attribute attribute){
      if(attribute instanceof UniqueAttribute)
        ((UniqueAttribute)attribute).setAsset(this);
      attributeList.add(attribute);
    }
    

    不幸的是,由于它们位于不同的包中,因此UniqueAttribute.setAsset()必须是公共的。这使得该方法对引擎的外部用户开放可以搞砸了,虽然我可以通过直接使用这种方法来解决它是一个错误 - 它似乎相当草率。

  2. 第二个选项是在构造时为UniqueAttribute提供Asset,这意味着创建时的代码看起来像这样:

    asset.addAttribute(new UniqueAttribute(asset));
    

    虽然我可以添加check-and-throwable或assert来确认传入了正确的资产,但我基本上依赖于用户来连接这两者,我也不愿意这样做。

    < / LI>
  3. 第三个选项是咬住子弹并将50个java文件全部放入同一个包中,以便我可以使用标准的可见性。

  4. 是否有某种图案或某种东西可以帮助将这两者联系在一起而不会暴露电线,或者迫使我将所有东西放入一个大包装中?

    不相关的咆哮:我一直不喜欢java中的子包的概念并没有真正以任何有意义的方式扩展。就java而言,一个子包只是一个不同的包,而且我有很多场合可以使用与此直接相关的更多可见性修饰符。

5 个答案:

答案 0 :(得分:2)

我的建议是Asset,Attribute和UniqueAttribute都应该在同一个包中(可能还有一些其他的核心“引擎”类)。然后,您可以使用UniqueAttribute.setAsset的标准包可见性。

您不需要将所有其他类放在同一个包中 - 您的Asset.addAttribute方法应该是公共的,并且可以从其他包访问,因此您的应用程序的其余部分可以直接使用它。

因此,您的分类中的解决方案可以称为“ 3 - ”。

作为一些更一般的观点,还要考虑:

  • 你是否真的需要Attributes和UniqueAttributes的复杂性 - 我不确定你真的这么做,以前实现了一个相当复杂的游戏对象模型而不需要任何看起来像UniqueAttribute的东西。如果UniqueAttribute“需要一个回链接”,那么也许它试图太聪明/做太多了?
  • 即使你确实需要两者,你真的想编写以相同的方式处理它们的代码/作为同一个对象的一部分吗?它们在概念上看起来很不一样,如果你把两者混为一谈,你最终会编写很多条件代码......
  • 属性具有一致的共享和不可变的各种其他优点 - 它对内存使用,并发性和可测试性等更好。而且由于它们可能非常小,因此在需要它的情况下,写入时复制语义的成本是微不足道的。

答案 1 :(得分:2)

我会在Attribute中添加一个回调方法,当属性的一个实例添加到资产时调用该方法:

class Attribute {
    protected void addedToAsset(Asset asset) {
        // do nothing
    }
}

此方法将在addAttribute方法

中调用
class Asset {
    public void addAttribute(Attribute attribute) {
       attributeList.add(attribute);
       attribute.addedToAsset(this);
    }

}

该方法将在UniqueAttribute中重写,以便控制与Asset:

的链接
class UniqueAttribute extends Attribute {
    Asset asset;
    protected void addedToAsset(Asset asset) {
        // manage the previous link if needed
        if (this.asset != null) { ... }
        this.asset = asset;
    }
} 

通过此解决方案,资产和属性应放在同一个包中。但UniqueAttribute可以在你想要的任何包中。

答案 2 :(得分:1)

修改你的第二个选项

asset.addAttribute(new UniqueAttribute(asset)); 
像这样:

class UniqueAttribute {
Asset asset;
     public UniqueAttribute(Asset asset) { this.asset = asset; asset.addAttribute(this); }
}

对非唯一属性执行类似的方法。这意味着不是从外部使用addAttribute(),而只是在构造函数中使用它。

另一个选择是向Asset:createAttribute()和createUniqueAttribute()添加两个工厂方法;

答案 3 :(得分:0)

嗯,基本上你想要做三件事:

  1. 使setAsset方法在包含Asset class
  2. 的包内可见
  3. 隐藏所有其他包中的setAsset方法
  4. 不要使用子包来实现
  5. 这有点问题:如果你在Attribute类中声明公共方法所有其他类,包括该包(让我们称之为AttributePackage),你无法阻止用户包含该包的某个地方。

    另一方面,您可以执行以下操作:

    1. 创建一个只包含用户应该使用的Attribute方法的接口,让我们称之为AttributeInterface
    2. make Attribute实现该接口
    3. 将AttributeInterface添加到新包
    4. 想要使用Attribute类的用户应该同时通过AttributeInterface使用它 资产将直接使用Attribute类,以便访问所有方法。

      我会举个例子:

      //attribute interface package
      public interface AttributeInterface{
           public void publicAttributeMethodClientShouldUse();
      }
      
      //attribute package
      public class Attribute{
           public void setAsset(Asset a);
           public void publicAttributeMethodClientShouldUse();
      }
      

      资产将直接引用属性,同时用户应引用AttributeInterface。希望明确。

答案 4 :(得分:0)

首先,这些实体似乎与放置在同一个包中的关系非常密切。我将它们放在同一个包中,并使addAttribute方法包变为私有。

请记住,自从在Java中引入AccessibleObject以来,语言中的可见性和访问控制已变得简单......使用您的库的任何人都可以获取您的类并使私有方法和字段可访问和修改!地狱,他们甚至可以修改final成员!因此,不要过分强调可见性方面,只需确保您的模型和方法流程对您的用户有意义并正常工作。