だから私は自分のクラスのオブジェクトのArrayListを持っています:
public class A
{...}
ここで、リストからこれらのオブジェクトの1つを保持する変数があるとします。これで、そのオブジェクトを変更した場合(たとえば、そのオブジェクトにフィールドを設定した場合)、オブジェクト自体を保持するメモリが変更されるため、両方の参照(リスト内のオブジェクトを保持する変数と内部配列変数)が引き続き使用されることがわかります。同一であり、両方とも同じ、現在変更されているオブジェクトに表示されます。通常の動作!
しかし、変数が指すリスト内のオブジェクトを置き換えるときにもそうなるようにしたいと思います。それは私がするときです
myList.set(theObjectPosition, newInstanceOfA);
...この場合、変数にこの新しいインスタンスへの参照を自動的に持たせたいと思います。そのような振る舞いを実装する最も簡単な方法は何でしょうか?
これが私がこれを必要とする理由です:
要するに、私はArrayListに加えられた変更の取り消し/やり直しを処理するクラスのセットを持っています(これは拡張していませんが、とにかく問題を解決しませんか?)。クラスは呼ばれます
UndoAction, Add, Remove, Modify (the latter 3 inherit from UndoAction)
すべてのクラスには、メソッドundo()とredo()があります。
説明による例(必要に応じてコードは最後にあります):
リストにアイテムを追加したいとします。新しいAdd(myObject)を実行し、次にリスト内のアイテムを変更して、新しいModify(myObject)を実行します。その後、バックアップとしてオブジェクト状態のDeepCopyを作成します。 、その後、オブジェクト自体を変更します(新しいModify(..)の呼び出しを行った後)。次に、Modifyオブジェクトでundo()を実行して、list.set(somePos、previousDeepCopy)を実行します(したがって、この投稿では、作成されたディープコピーは、本質的に、物事を台無しにする新しいインスタンスです!!!)...
したがって、このlist.setがいくつかの問題を引き起こすことを想像できます。置き換えられたオブジェクトへの参照はすべて失われます。そのため、そのようなオブジェクトへの参照が常に置き換えられる場合、そのようなリストを効果的に操作することはできません。したがって、私の元に戻るマネージャーは、この方法で失敗する運命にあります。
では、これらの設計上の欠陥とどのように戦うのでしょうか?どんな提案でも大歓迎です。
いくつかのコード:
protected abstract class UndoAction {
protected HashSet<Integer> ids = new HashSet<Integer>();
protected Marker marker;
public UndoAction(List<E> l) {
for (E e : l) {
if (!entities.contains(e)) {
entities.add(e);
trace.append(entities.indexOf(e), new Stack<UndoAction>());
}
ids.add(entities.indexOf(e));
}
}
public boolean sameAffectedTargets(UndoAction undoAction) {
if (this.ids.containsAll(undoAction.ids) && undoAction.ids.containsAll(this.ids))
return true;
return false;
}
public Marker getMarker() {
return new Marker(this);
}
public void firstRun() {
}
public void undo() {
}
public void redo() {
}
protected List<Data> getCopyEntities() {
List<Data> l = new ArrayList<Data>();
for (Integer id : ids) {
E e = entities.get(id);
int pos = adapterList.indexOf(e);
l.add(new Data(id, pos, e));
}
return l;
}
protected List<Data> getDeepCopyEntities() {
List<Data> l = new ArrayList<Data>();
for (Integer id : ids) {
E e = DeepCopy.copy(entities.get(id));
int pos = adapterList.indexOf(entities.get(id));
l.add(new Data(id, pos, e));
}
return l;
}
public void addEntities(List<Data> datas) {
for (Data d : datas)
d.addEntity();
}
public void setEntities(List<Data> datas) {
for (Data d : datas)
d.setEntity();
}
public void removeEntities(List<Data> datas) {
for (Data d : datas)
d.removeEntity();
}
protected class Data {
public int id;
public int pos;
public E entity;
public void addEntity() {
entities.set(this.id, this.entity);
adapterList.add(this.pos, this.entity);
}
public void setEntity() {
entities.set(this.id, this.entity);
E oldEntity = adapterList.get(this.pos);
adapterList.set(this.pos, this.entity);
notifyEntityReplaced(oldEntity, adapterList.get(this.pos), this.pos);
}
public void removeEntity() {
entities.set(this.id, null);
adapterList.remove(this.entity);
}
public Data(int id, int pos, E entity) {
this.id = id;
this.pos = pos;
this.entity = entity;
}
}
}
protected class Add extends UndoAction {
protected List<Data> addBackup;
public Add(List<E> l) {
super(l);
}
@Override
public void undo() {
super.undo();
addBackup = getCopyEntities();
removeEntities(addBackup);
}
@Override
public void firstRun() {
super.firstRun();
adapterList.addAll(entities);
}
@Override
public void redo() {
super.redo();
addEntities(addBackup);
}
}
// call before modifying
protected class Modify extends UndoAction {
protected List<Data> beforeDeepCopies;
protected List<Data> afterDeepCopies;
public Modify(List<E> l) {
super(l);
}
@Override
public void undo() {
super.undo();
if (!skipModifying) {
if (afterDeepCopies == null)
afterDeepCopies = getDeepCopyEntities();
setEntities(beforeDeepCopies);
}
}
@Override
public void firstRun() {
super.firstRun();
if (!skipModifying) // TODO
beforeDeepCopies = getDeepCopyEntities();
}
@Override
public void redo() {
super.redo();
if (!skipModifying)
setEntities(afterDeepCopies);
}
}
protected class Remove extends UndoAction {
protected List<Data> removeBackup;
public Remove(List<E> l) {
super(l);
}
public List<E> getRemoved() {
List<E> l = new ArrayList<E>();
for (Data data : removeBackup)
l.add(data.entity);
return l;
}
@Override
public void undo() {
super.undo();
addEntities(removeBackup);
}
@Override
public void firstRun() {
super.firstRun();
removeBackup = getCopyEntities();
}
@Override
public void redo() {
super.redo();
removeEntities(removeBackup);
}
}