Vervolledig het all-in-project “Map Maker”. Inclusief interfaces en is/as .Kan je zelf extra zaken toevoegen zoals andere kamers, andere functionaliteit, etc.
We willen nu ervoor zorgen dat wanneer we volgende code schrijven, dat ook alle elementen van het Salon mee verhuizen naar de nieuwe locatie:
List<MapObject> allObjects = new List<MapObject>(); allObjects.Add(new SalonElement(new Point(5, 5))); allObjects[0].Paint(); //Verplaats salon allObjects[0].Location= new Point(10,10); allObjects[0].Paint();
Echter, dat gebeurt niet. De oplossing is een gevorderd principe, maar eentje dat hopelijk het voordeel van een Interface laat zien.
We leggen een nieuwe interface IComposite vast die iedere composietklasse moet implementeren:
interface IComposite { void UpdateElements(Point offset); }
Ons SalonElement wordt krijgt dan volgende aanpassing:
class SalonElement: MapObject,IComposite { private List<MapObject> elementen= new List<MapObject>(); public SalonElement(Point salonLoc) { ... } public override void Paint() { ... } public void UpdateElements(Point offset) { ... } }
De UpdateElements methode zou er dan als volgt kunnen uitzien:
for (int i = 0; i < elementen.Count; i++) { Point elementLoc = elementen[i].Location; elementLoc.X += offset.X; elementLoc.Y += offset.Y; elementen[i].Location = elementLoc; }
Telkens we dus UpdateElements aanroepen dan worden alle elementen die bij het object horen ook geüpdatet.
Nu rest ons nog één aanpassing, dat is ervoor zorgen dat deze methode ook effectief telkens wordt aangeroepen. De methode moet aangeroepen worden telkens we een aanpassing aan de Location van het SalonElement doen. Hierbij controleren we eerst of de locatie überhaupt al geïnitialiseerd is (anders is deze waarde gelijk aan ‘null’). Vervolgens berekenen we de offset, dit is het verschil tussen de huidige en de nieuwe locatie van de composietklasse. Daar Location bij MapObject hoort, moeten we dus in die klasse een aanpassing doen. We bereiden daarom de Locationproperty uit als volgt:
public Point Location { get { return location; } set { Point prevloc = location; Point offset = new Point(1, 1); if (location != null) { offset.X = value.X - prevloc.X; offset.Y = value.Y - prevloc.Y; } location = value; if (this is IComposite) { IComposite obj = this as IComposite; obj.UpdateElements(offset); } } }
Deze code kan misschien wat toelichting gebruiken:
We kunnen nu dus zelfs een volledig Huis als klasse beschrijven en zo verschillende soorten huizen definiëren. Telkens we dan een huis verplaatsen dan verplaatst de hele inboedel mee.
Belangrijk: Het gebruik van de interface is hier louter illustratief. Dit probleem kan je beter oplossen door een CompositeElement klasse aan te maken die overerft van MapObject. Deze klasse bevat dan een lijst van elementen en een UpdateElements methode. In MapObject controleer je dan of een object van het type CompositeElement is (ipv IComposite)
Een nog betere oplossing is die waarbij je gewoon direct zegt dat MapObject een lijst van elementen kan bevatten. Als een MapObject exact 1 element in zijn lijst bevat dan is de werking dezelfde als ervoor, maar nu kunnen we dus zonder veel code aanpassingen ook composiet objecten aanmaken.
Think about it.