我正在用Java设计游戏引擎。
这个引擎的核心存在两个类Asset和Attribute,其中Asset有一个Attributes列表。大多数属性不需要链接回其属性,这意味着属性可以并且经常出现在多个资产的列表中。但是,存在一个名为UniqueAttribute的属性扩展,它是特定于其资产的属性的实现,并使用链接。
理想情况下,如果我删除其他代码,我的Asset的addAttribute方法看起来就像这样:
public void addAttribute(Attribute attribute){
if(attribute instanceof UniqueAttribute)
((UniqueAttribute)attribute).setAsset(this);
attributeList.add(attribute);
}
不幸的是,由于它们位于不同的包中,因此UniqueAttribute.setAsset()必须是公共的。这使得该方法对引擎的外部用户开放可以搞砸了,虽然我可以通过直接使用这种方法来解决它是一个错误 - 它似乎相当草率。
第二个选项是在构造时为UniqueAttribute提供Asset,这意味着创建时的代码看起来像这样:
asset.addAttribute(new UniqueAttribute(asset));
虽然我可以添加check-and-throwable或assert来确认传入了正确的资产,但我基本上依赖于用户来连接这两者,我也不愿意这样做。
< / LI>第三个选项是咬住子弹并将50个java文件全部放入同一个包中,以便我可以使用标准的可见性。
是否有某种图案或某种东西可以帮助将这两者联系在一起而不会暴露电线,或者迫使我将所有东西放入一个大包装中?
不相关的咆哮:我一直不喜欢java中的子包的概念并没有真正以任何有意义的方式扩展。就java而言,一个子包只是一个不同的包,而且我有很多场合可以使用与此直接相关的更多可见性修饰符。
答案 0 :(得分:2)
我的建议是Asset,Attribute和UniqueAttribute都应该在同一个包中(可能还有一些其他的核心“引擎”类)。然后,您可以使用UniqueAttribute.setAsset的标准包可见性。
您不需要将所有其他类放在同一个包中 - 您的Asset.addAttribute方法应该是公共的,并且可以从其他包访问,因此您的应用程序的其余部分可以直接使用它。
因此,您的分类中的解决方案可以称为“ 3 - ”。
作为一些更一般的观点,还要考虑:
答案 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)
嗯,基本上你想要做三件事:
这有点问题:如果你在Attribute类中声明公共方法所有其他类,包括该包(让我们称之为AttributePackage),你无法阻止用户包含该包的某个地方。
另一方面,您可以执行以下操作:
想要使用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
成员!因此,不要过分强调可见性方面,只需确保您的模型和方法流程对您的用户有意义并正常工作。