在我对Java的理解中,设置类对象的实例变量的最常用方法是:
让我们说我的main()有一个类bigA的对象,它包含一个类littleA对象(包含实例变量)的集合,以及类bigB的另一个对象,它包含类littleB对象的集合(它有来自littleA的不同实例变量)。如何编写一个方法来同时修改一个或多个littleA和littleB对象的实例变量?
(注意:我怀疑这是一个常见的问题,但我搜索过但没有找到它。也许我使用了错误的术语。)
编辑:更具体的例子:让我们说我是垄断者。玩家有钱(各种面额)和财产(有些有房子)。她想将一些房产升级到酒店。房屋和酒店都需要增加和减少金钱。我知道如何使用pass-by-reference语言执行此操作,但不使用pass-by-value,除非我将整个游戏状态转换为一个巨大的对象并传递它,这似乎是很多内存改组而且基本上和使用全局变量一样,这很糟糕,对吧?
答案 0 :(得分:0)
如果我正确理解你的问题,你可以在bigA / bigB类上编写一个方法来获取你想要设置的值,然后遍历设置实例变量的littleA / B对象集合。像:
// Assuming Foo has a member collection of smallFoo
Foo A = new Foo();
// do stuff that populates the collection of smallFoo in A
A.setSmallFooZipCode("23444");
public void setSmallFooZipCode(String zip_ {
// for thisSmallFoo in smallFoo
thisSmallFoo.setZip(zip);
// end for
)
答案 1 :(得分:0)
对象(包括你的容器对象)应该代表某些东西 - 用A / B来思考它们会让它变得有点困难。
最重要的是,如果你总是一次修改两个类中的属性,我会建议代码味道很差......
在我的脑海中,我无法想到任何我用这种方式建模的东西,所以很难想出一个例子。 A和B应该包含在父ab类中(并且该类应该具有该属性),或者a和b应该是相同的接口 - 在任何一种情况下,这些都将进入父容器中的单个集合。 / p>
所以说,你应该在父容器对象上有一个方法来完成工作。在大多数情况下,它不应该像“setAttribute ...”这样的方法,它应该是像“doAction”这样的方法。换句话说,如果你的容器是一个“Herd”并且它包含一堆大象,那么你会告诉Herd移动到某个位置并让Herd对象向每个大象发送消息告诉它去哪里。 / p>
如果你想到的方法是“要求对象为你做某事”而不是对某个对象进行操作,那么这有助于使这些决定变得更加容易。
答案 2 :(得分:0)
您只需将BigA
和BigB
封装在另一个对象中:
class BigWrapper {
private BigA bigA;
private BigB bigB;
public void someMethod() {
bigA.someMethod();
bigB.someMethod();
}
}
someMethod()
中的 BigA
会修改LittleA
个实例。 BigB
:
class BigB {
private LittleA[] littles;
public void someMethod() {
//do something with the littles
}
}
当然,此解决方案不允许您指定要定位的 Little
个实例,以及不会&#39 ; t允许您指定应该执行的行为(通过littles调用哪种特定方法)。
如果您想要这种灵活性,请使用回调:
interface Little { }
class LittleA implements Little { }
class LittleB implements Little { }
interface Callback<T extends Little> {
void perform(int currentIndex, T currentLittle);
}
class CallbackHandler<T extends Little> {
private int[] indexes;
private Callback<T> callback;
public CallbackHandler(int[] indexes, Callback<T> callback) {
this.indexes = indexes;
this.callback = callback;
}
public void perform(T[] littles) {
for(int i = 0; i < indexes.length; i++) {
int index = indexes[i];
callback.perform(i, littles[index]);
}
}
}
class BigWrapper {
private BigA bigA;
private BigB bigB;
public BigWrapper(BigA bigA, BigB bigB) {
this.bigA = bigA;
this.bigB = bigB;
}
public void perform(CallbackHandler<LittleA> aCallback, CallbackHandler<LittleB> bCallback) {
bigA.perform(aCallback);
bigB.perform(bCallback);
}
}
class BigA {
private LittleA[] littles;
public BigA(LittleA[] littles) {
this.littles = littles;
}
public void perform(CallbackHandler<LittleA> callback) {
callback.perform(littles);
}
}
class BigB {
private LittleB[] littles;
public BigB(LittleB[] littles) {
this.littles = littles;
}
public void perform(CallbackHandler<LittleB> callback) {
callback.perform(littles);
}
}
CallbackHandler
将实际回调映射到您要定位的索引。
所以你首先要创建回调:
Callback<LittleA> aCallback = (currentIndex, currentLittle) -> {
//do what you want to the littles
};
然后将其传递给CallbackHandler
,它允许您指定要定位的索引:
int[] indexes = { 0, 1, 2 };
CallbackHandler<LittleA> aCallbackHandler = new CallbackHandler<>(indexes, aCallback);
BigWrapper
公开perform(CallbackHandler<LittleA>, CallbackHandler<LittleB>)
,因此您可以将处理程序传递给该方法。
MCVE看起来像:
public static void main(String[] args) {
LittleA[] littleA = {
new LittleA(),
new LittleA(),
new LittleA()
};
LittleB[] littleB = {
new LittleB(),
new LittleB(),
new LittleB()
};
BigA bigA = new BigA(littleA);
BigB bigB = new BigB(littleB);
BigWrapper big = new BigWrapper(bigA, bigB);
Callback<LittleA> aCallback = (index, little) -> {
//...
};
Callback<LittleB> bCallback = (index, little) -> {
//...
};
CallbackHandler aCallbackHandler = new CallbackHandler(new int[] { 2, 3, 4 }, aCallback);
CallbackHandler bCallbackHandler = new CallbackHandler(new int[] { 5, 6, 7 }, bCallback);
big.perform(aCallbackHandler, bCallbackHandler);
}