我遇到的情况是我总是需要运行一些依赖于对象本身的代码
public abstract class A{
public A(X x){
//init A stuff
x.getAList("stuff").add(this);
x.getAList("otherstuff").add(this);
}
}
public class B extends A{
public B(X x){
super(x);
//init B stuff
}
}
public class C extends A{
public C(X x){
super(x);
//init C stuff
x.getAList("otherstuff").remove(this);
x.getAList("morestuff").add(this);
}
}
public class SomeClass{
private X someX;
public A somefunc(boolean b){
if(b){
return new B(someX);
}else{
return new C(someX);
}
}
}
问题如下。在这个例子中,我在构造函数中使用this
。如果另一个线程试图通过someX.getAList访问该对象,则可能导致该线程在构造函数结束之前访问该对象。
你可以这样做,以便通过somefunc
将对象添加到AList中public class SomeClass{
private X someX;
public A somefunc(boolean b){
A a;
if(b){
a = new B(someX);
someX.getAList("stuff").add(a);
someX.getAList("otherstuff").add(a);
}else{
a = new C(someX);
someX.getAList("stuff").add(a);
someX.getAList("morestuff").add(a);
}
return a;
}
}
问题是B&C和C也可以在其他地方实例化,每次创建B或C时,都需要以指定的方式添加。我不想将对象添加到AList是用户的责任,而是类的责任。我也不希望用户必须调用为他们执行此操作的init函数。另一方面,我不想要任何并发问题。
是否存在可以实现此目的的方法或模式?
Golang有类似defer的东西,可以在函数/ method / constructor完成后运行一段代码。
答案 0 :(得分:9)
为super和subclass创建一个Factory-Method,并使构造函数成为私有,强制每个想要实例的人使用工厂方法。工厂方法是返回完全构造的实例的方法。一旦实例被完全构造(在工厂方法中调用构造函数之后)将实例添加到列表中,这样就没有线程可以获得不完整/未完成的实例。
工厂方法的要点是严格地将所有初始化代码与任何非初始化代码隔离,以避免访问和暴露未初始化的字段。此外,它还可以作为用户的选择器,自动返回合适的(子)类型,而无需指定。(Interesting design-patterns)
abstract class A{
protected A(){
//constructor code goes here
}
public void afterFinalisation(final X x) {
x.getAList("stuff").add(this);
x.getAList("otherstuff").add(this);
}
}
class B extends A{
protected B(){
super();
//constructor code goes here
}
public static B create(final X x) {
final B returnValue = new B();
returnValue.afterFinalisation(x);
return returnValue;
}
}
class C extends A{
protected C(){
super();
//constructor code goes here
}
@Override
public void afterFinalisation(final X x) {
super.afterFinalisation(x);
x.getAList("otherstuff").remove(this);
x.getAList("morestuff").add(this);
}
public static C create(final X x) {
final C returnValue = new C();
returnValue.afterFinalisation(x);
return returnValue;
}
}
class SomeClass{
private final X someX = new X();
public A somefunc(final boolean b){
if(b){
return B.create(this.someX);
}else{
return C.create(this.someX);
}
}
}
构造函数代码的功劳归于coolcats iteration of my answer,我试图避免将代码放入受保护的构造函数中,而是使用init()方法,这需要对最终字段进行大量的无法解决的方法。
答案 1 :(得分:1)
通过HopfullyHelpful做出一些设计决定,我最终喜欢以下设计:
public abstract class A{
protected A(X x){
//constructor with all inits
}
protected A publish(X x) {
x.getAList("stuff").add(this);
x.getAList("otherstuff").add(this);
return this;
}
}
class B extends A{
protected B(X x){
super(x);
//constructor with all inits
}
protected B publish(X x) {
super.publish(x);
return this;
}
public static B create(X x) {
return new B(x).publish(x);
}
}
class C extends A{
protected C(X x){
super(x);
//constructor with all inits
}
protected void publish(X x) {
super.publish(x);
x.getAList("otherstuff").remove(this);
x.getAList("morestuff").add(this);
return this;
}
public static C create(X x) {
return new C(x).publish(x);
}
}
class SomeClass{
private X someX;
public A somefunc(boolean b){
if(b){
return B.create(this.someX);
}else{
return C.create(this.someX);
}
}
}