views:

34

answers:

1

I have some points (car stops) to represent on a time graph. These points are linked between them by lines. Points + Lines represent a Graph (that is a car schedule). The Graph can be modified by moving CarStops in time with the mouse.

I decided to implement Points and Lines as controls (thought that will be easier to move them on the panels).

I have two business object layers – Real BO (CarStop) and GUI Control (CarStopControl). I associate then a CarStop(Time, Station) to a CarStopControl(X, Y) - CarStopControl subscribes to CarStop.Moved events.

Finally, a Car object has some CarStops.

  • How do I move controls? Simply: Detect a mouse move on the panel and compute dX, transform dX in dTime Car.Move(dTime) – moves all the CarStops. When CarStop moved, send event to CarStopControl, and the latter change its coordinates. In this way CarStopControl seems to follow the mouse movements.

This is all.


The problem appeared when in Car.Move there was a need to recreate the CarStop collection – the links between CarStopControl and CarStop obviously became obsolete, car BO Car and CarStop does not care nor even know about CarStopControls.

The similar situation is when Car itself could be replaced by a new Car.

Had someone similar situations? Is there a "workaround" of +- quickly fix this problem?

Thanks.

A: 

My first idea is to introduce an extra level of indirection. Instead of the real CarStop and Car objects, your controls could be subscribers to proxy objects (implementing the same interface), which then in turn know their "real" buddy and are able to update the reference to their buddy when latter is replaced with a new one.

interface ICarStop {
    void addObserver(CarStopObserver observer);
    void removeObserver(CarStopObserver observer);
}

class CarStopControl implements CarStopObserver {
    public void update (ICarStop obj, Object arg) {
        // ...
    }
}

class CarStopProxy implements ICarStop {
    ICarStop original;
    public CarStopProxy(ICarStop original) {
        this.original = original;
    }
    public void setOriginal(ICarStop original) {
        this.original = original;
    }
    public void addObserver(CarStopObserver observer) {
        // ...
    }
    public void removeObserver(CarStopObserver observer) {
        // ...
    }
    public void notifyObservers(Object object) {
        // iterate through observers an update each
    }
}

class CarStop implements ICarStop {
    CarStopProxy proxy;
    public CarStop(CarStopProxy proxy) {
        this.proxy = proxy;
    }
    public CarStop(CarStop other) {
        // copy all properties
        this.proxy = other.proxy;
    }
    public CarStopProxy getProxy() {
        return proxy;
    }
    public void setProxy(CarStopProxy proxy) {
        this.proxy = proxy;
    }
    public void handleChange() {
        proxy.notifyObservers(...);
    }
}

Now, when you need to replace a CarStop object, you write:

CarStop newCarStop = new CarStop(oldCarStop);
// update all references to point to the new object
oldCarStop.setProxy(null);

Another possibility would be to introduce a Mediator, which would be able to identify model objects by some sort of identifier (different from their concrete address / reference, as that can change). In this case, when a CarStop object is replaced by another one, the new one just takes over the ID of its predecessor, and uses it in its update messages:

class CarStop implements ICarStop {
    Mediator mediator;
    Long id;
    public CarStop(Mediator mediator) {
        this.mediator = mediator;
    }
    public CarStop(CarStop other) {
        // copy all properties
        this.mediator = other.mediator;
    }
    public void handleChange() {
        mediator.notifyObservers(id, ...);
    }
}

CarStop newCarStop = new CarStop(oldCarStop);
// update all references to point to the new object
Péter Török
Let's say instead of myCarStop in CarStopControl I introduced myCarStopProxy that implements ICarStop. Now I recteate the CarStop. How the CarStopProxy knows about? Where should I create the proxy: in the BO or GUI layer?
serhio
I have ID's in my cars-carStops from the DataBase. Now, Mediator, like carStopProxy, where it shoudl be created. Now is it informed about a carStop reset...
serhio
@serhio I added code examples.
Péter Török
why do you need CarStopObserver? your CarStop does not implement ICarStop add/removeObserver... and this `CarStop newCarStop = new CarStop(oldCarStop);` is impossible to have everytime. Sometiems just I set a new collection of CarStops in the Car instead of the old one...
serhio
@serhio You wrote "`CarStopControl` subscribes to `CarStop.Moved` events", so I assumed there is some sort of Observer is working in there, that's why I hacked in half of an `Observer` implementation - leaving out parts not to hide the main point of the example. Feel free to omit or replace it with your preferred way. The CarStop copy constructor is just a convenience method, if you don't need to copy anything from the old car stop to the new one, you can leave it out.
Péter Török