Java 当父类型始终是子类时,如何将整个层次结构设计为具有*不可变*父字段?
继承人:Java 当父类型始终是子类时,如何将整个层次结构设计为具有*不可变*父字段?,java,oop,design-patterns,Java,Oop,Design Patterns,继承人: LineEntityType SingleLineEntity BlockEntity 块可以包含其他块或单线图元。所有实体都可以有一个父实体,它始终是块实体 我想这样做: BlockEntity rootBlock = new BlockEntity(...); block.assignChildren(new LineEntityType[] { new SingleLineEntity(...) new BlockEntity(...) new
LineEntityType
SingleLineEntity
BlockEntity
块可以包含其他块或单线图元。所有实体都可以有一个父实体,它始终是块实体
我想这样做:
BlockEntity rootBlock = new BlockEntity(...);
block.assignChildren(new LineEntityType[] {
new SingleLineEntity(...)
new BlockEntity(...)
new BlockEntity(...)});
因此,父块对象(rootBlock
)复制每个子块(防御副本),同时将自身添加为父块:
BlockEntity(LineEntityType[] children) {
for(LineEntityType[] children) {
//Duplicate the array
childEntitiesWithParentAssigned = Arrays.copyOf(children, children.length);
//Duplicate each child, adding "this" as the parent
for(int i = 0; i < children.length; i++) {
child = childEntitiesWithParentAssigned[i];
childEntitiesWithParentAssigned[i] = child.getCopyWithParentAssigned(this);
}
}
}
我唯一想到的另一件事是在分配其子级之前明确地分配父级:
//null: No parent
BlockEntity rootBlock = new BlockEntity(..., null);
LineEntityType children = new LineEntityType[] {
new SingleLineEntity(..., rootBlock)
new BlockEntity(..., rootBlock)
new BlockEntity(..., rootBlock)});
rootBlock.setChildren(children);
但这要求children字段是可变的
关于如何重新考虑这一点,以便父字段可以由父字段分配,但不可变并避免循环依赖,有什么想法吗
谢谢。如果
parent
是LineEntityType
的final
字段,则LineEntityType
的构造函数必须接收应存储在那里的引用。我不太清楚您所看到的“循环依赖”问题,因为子节点的构造函数可以从自身正在构造的父节点的构造函数中调用,并接收对正在构造的父对象的引用。在完全构造父节点之前,它实际上不应该尝试对该引用标识的父节点执行任何操作,但这并不意味着它不能存储该引用。如果parent
是LineEntityType
的最终字段,然后LineEntityType
的构造函数必须接收应该存储在那里的引用。我不太清楚您所看到的“循环依赖”问题,因为子节点的构造函数可以从自身正在构造的父节点的构造函数中调用,并接收对正在构造的父对象的引用。在完全构造父节点之前,它实际上不应该尝试对该引用标识的父节点执行任何操作,但这并不意味着它不能存储该引用。如果parent
是LineEntityType
的最终字段,然后LineEntityType
的构造函数必须接收应该存储在那里的引用。我不太清楚您所看到的“循环依赖”问题,因为子节点的构造函数可以从自身正在构造的父节点的构造函数中调用,并接收对正在构造的父对象的引用。在完全构造父节点之前,它实际上不应该尝试对该引用标识的父节点执行任何操作,但这并不意味着它不能存储该引用。如果parent
是LineEntityType
的最终字段,然后LineEntityType
的构造函数必须接收应该存储在那里的引用。我不太清楚您所看到的“循环依赖”问题,因为子节点的构造函数可以从自身正在构造的父节点的构造函数中调用,并接收对正在构造的父对象的引用。在完全构造父节点之前,它实际上不应该尝试对该引用标识的父节点执行任何操作,但这并不意味着它不能存储该引用。听起来你基本上是在说“我希望Foo指向Bar,Bar指向Foo,但也希望两者都是不可变的”。一般来说,这些是相互矛盾的需求(必须首先创建一个对象,此时为时已晚)
唯一的解决方法是在构建另一个的过程中创建一个。您可以使用构建器模式的某些变体来保持这种状态:
// Immutable
class Foo {
private final Bar bar;
public Foo(BarBuilder builder) { this.bar = builder.create(this); }
}
// Immutable
class Bar {
private final Foo foo;
public Bar(Foo foo) { this.foo = foo; }
}
class BarBuilder {
public Bar create(Foo foo) { return new Bar(foo); }
}
Foo foo = new Foo(new BarBuilder());
Bar bar = foo.bar;
将这一点应用到您的特定设计中,留给读者作为练习…听起来您基本上是在说“我希望Foo指向Bar,Bar指向Foo,但也希望两者都是不可变的”。一般来说,这些是相互矛盾的需求(必须首先创建一个对象,此时为时已晚)
唯一的解决方法是在构建另一个的过程中创建一个。您可以使用构建器模式的某些变体来保持这种状态:
// Immutable
class Foo {
private final Bar bar;
public Foo(BarBuilder builder) { this.bar = builder.create(this); }
}
// Immutable
class Bar {
private final Foo foo;
public Bar(Foo foo) { this.foo = foo; }
}
class BarBuilder {
public Bar create(Foo foo) { return new Bar(foo); }
}
Foo foo = new Foo(new BarBuilder());
Bar bar = foo.bar;
将这一点应用到您的特定设计中,留给读者作为练习…听起来您基本上是在说“我希望Foo指向Bar,Bar指向Foo,但也希望两者都是不可变的”。一般来说,这些是相互矛盾的需求(必须首先创建一个对象,此时为时已晚)
唯一的解决方法是在构建另一个的过程中创建一个。您可以使用构建器模式的某些变体来保持这种状态:
// Immutable
class Foo {
private final Bar bar;
public Foo(BarBuilder builder) { this.bar = builder.create(this); }
}
// Immutable
class Bar {
private final Foo foo;
public Bar(Foo foo) { this.foo = foo; }
}
class BarBuilder {
public Bar create(Foo foo) { return new Bar(foo); }
}
Foo foo = new Foo(new BarBuilder());
Bar bar = foo.bar;
将这一点应用到您的特定设计中,留给读者作为练习…听起来您基本上是在说“我希望Foo指向Bar,Bar指向Foo,但也希望两者都是不可变的”。一般来说,这些是相互矛盾的需求(必须首先创建一个对象,此时为时已晚)
唯一的解决方法是在构建另一个的过程中创建一个。您可以使用构建器模式的某些变体来保持这种状态:
// Immutable
class Foo {
private final Bar bar;
public Foo(BarBuilder builder) { this.bar = builder.create(this); }
}
// Immutable
class Bar {
private final Foo foo;
public Bar(Foo foo) { this.foo = foo; }
}
class BarBuilder {
public Bar create(Foo foo) { return new Bar(foo); }
}
Foo foo = new Foo(new BarBuilder());
Bar bar = foo.bar;
将此应用于您的特定设计是留给读者的一个练习…在阅读了评论和答案后,在车里思考了一个小时左右,我决定ChildEntity
和ParentEntity
接口可以让它工作,尽管它确实需要接口之间的循环依赖关系
interface ChildEntity {
int getLevelsBelowRoot();
ParentEntity getParent();
ParentEntity getTopParent();
ChildEntity getCopyWithParentAssigned(ParentEntity parent);
}
interface ParentEntity extends ChildEntity {
int getChildCount();
}
public abstract class AbstractLineEntity implements ChildEntity
class SingleLineEntity extends AbstractLineEntity
class BlockEntity extends AbstractLineEntity implements ParentEntity
现在,一切都可以是不变的,这是首要目标。正如其他人所建议的,我不确定是否有可能避免循环依赖,因为所有孩子都有父母,父母也可以是孩子。现在,我很高兴