views:

55

answers:

3

Hello,

I'm trying to figure out the best design pattern to insulate a child object from knowing too much about the parent object it is contained in.

For instance, with a parent class like this...

class Airplane {
  var seats:Array
  ...

  function removeSeat(seat:Seat) {
    // find seat object in seats array and remove it
  }
}

child class...

class Seat {
  var rowNumber:int
  ...
}

If I'm working in the context of the Seat object and I want to remove myself from my parent Airplane object, what is the best way of separating the Seat from knowing about where it is in the Airplane.seats array?

I know I can pass the Airplane parent object into the constructor of the Seat, then call the removeSeat method on Airplane to remove that Seat, but I want to the Seat knowing as little about the Airplane if possible. Any ideas?

A: 

In order to keep this separation, the context where you access seats should also know witch airplane they belong. Ex:

class AirplaneService {
   public function removeEmptySeats(Airplane airplane) {
      foreach seat in airplane {
         if seat is empty {
            airplane.removeSeat(seat);
         }
      }
   }

   public function removeRowSeats(Airplane airplane, int rowNumber) {
      foreach seat in airplane {
         if seat.getRowNumber() == rowNumber {
            airplane.removeSeat(seat);
         }
      }
   }
}
bruno conde
+2  A: 

You could use the event handler pattern - essentially the airplane passes a 'removeMe' callback into the Seat on construction. The Seat then executes this callback when it wants to be removed. The seat has no idea who passed in the callback - it just needs to know the signature of the callback, in this example that the first parameter is a reference to a Seat object.

E.g. in pseudo-code

class Airplane {
   // will be passed in as callback
  function removeSeat(seat) {
    array.remove(seat);
  }
  ..
  var seat = new Seat();
  seat.removeCallback = removeSeat;
  ..
 }

class Seat() {
    removeCallback = null;
    ...
    ...
    // when we want to remove the seat, run the callback if set
    if (removeCallback !== null) { 
      removeCallback(this);
    }
 }
Ben Clayton
+1  A: 

Try implementing a variation of the Visitor pattern.

interface SeatContainer {

    function removeSeat(seat:Seat);

}

Then your airplane implements the interface

class Airplane implements SeatContainer {
  var seats:Array
  ...

  function removeSeat(seat:Seat) {
    // find seat object in seats array and remove it
  }
}

And your seat hold a reference to the interface

class Seat {
  var container:Container
  ...
  function removeMyself() {
     container.removeSeat(this);
  }
}

This way, the Seat object ignores what kind of container is in, being isolated of the actual implementation of the SeatContainer: it could be a Car, a Cinema, a Boat, or whatever implementation of SeatContainer interface.

Tomas Narros
That's a good solution, but just for claritie's sake, that is in no way related to the GoF Visitor pattern.
munificent