Hydra schreef op woensdag 06 april 2011 @ 12:05:
[...]
Inderdaad. Ik gebruik het zelf bijna nooit omdat ik het meestal niet nodig heb. In heel enkele gevallen heb je een collectie objecten die verder niet gerelateerd zijn waarvan je moet gaan uitvogelen van welk type ze zijn. Mag je mij gaan uitleggen hoe je dat kan doen zonder instanceof, dat visitor-pattern hierboven werkt dan niet.
Ok, misschien moet ik mezelf wat verduidelijken:
Ten eerste heb ik nooit geclaimd dat instanceof
per definitie evil is, alleen dat ik het lelijk vind voor objectoriëntatie waar behoorlijke abstractie beter op z'n plek is. Dogma's moeten ten alle tijden vermeden worden IMO (en ja ik snap de ironie van deze zin dus het heeft geen zin daarop in te gaan

).
Je hebt overigens wel gelijk, als je de situatie tegenkomt waarin je stuk voor stuk moet gaan uitvogelen welk runtime-type elk object in een collectie heeft dan kan je niet om de instanceof heen. Maar in mijn ervaring is dat vaak al een symptoom van slecht ontwerp, en dan steek ik liever mn tijd in het uit elkaar trekken van zo'n collection in een aantal collection objects die een type hebben die wat lager in die hierarchie zit, dan doorgaan met die slechte code.
Ten tweede is er nooit een "one size fits all" oplossing, de enige 100% generieke uitspraak die er gedaan kan worden is iets van de strekking "beslis a.d.h.v. de situatie welk patroon het meest geschikt is". Het probleem met deze uitspraak is natuurlijk dat er niets over specifieke situaties wordt gezegd.
Zelf zou ik t, als ik van scratch zou klussen, denk ik als volgt oplossen in productiecode (voor een supersimpel voorbeeld maakt het eigenlijk niet uit maar dit vind ik wel mooie code):
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| public abstract class FurnitureItem {
private final String id;
public FurnitureItem(String id) {
super();
this.id = id;
}
public String getId() {
return id;
}
public abstract void place();
} |
Java:
1
2
3
4
5
6
7
8
| public abstract class OpenableFurnitureItem extends FurnitureItem {
public OpenableFurnitureItem(String id) {
super(id);
}
protected abstract void onOpen();
} |
Java:
1
2
3
4
5
6
7
8
| public abstract class Seat extends FurnitureItem {
public Seat(String id) {
super(id);
}
protected abstract void onSitOn();
} |
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public class Closet extends OpenableFurnitureItem {
public Closet(String id) {
super(id);
}
@Override
protected void onOpen() {
System.out.println("Opened " + getId());
}
@Override
public void place() {
System.out.println("Placed " + getId() + " somehere");
// Some Closet-specific stuff
}
} |
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public class Couch extends Seat {
public Couch(String id) {
super(id);
}
@Override
protected void onSitOn() {
System.out.println(getId() + " is being sat on.");
}
@Override
public void place() {
System.out.println("Placed " + getId() + " somehere");
// Some Couch-specific stuff
}
} |
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public class User {
private String name;
public User(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void sitOn(Seat seat) {
System.out.println(this.name + " takes a seat on " + seat.getId());
seat.onSitOn();
}
public void open(OpenableFurnitureItem ofi) {
System.out.println(this.name + " opens " + ofi.getId());
ofi.onOpen();
}
} |
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| public class Main {
private static final int NUM_ITEMS = 3;
public static void main(String[] args) {
User user = new User("Jack Daniels");
OpenableFurnitureItem[] openables = new OpenableFurnitureItem[NUM_ITEMS];
Seat[] seats = new Seat[NUM_ITEMS];
for (int i = 0; i < NUM_ITEMS; i++) {
openables[i] = new Closet("Closet " + i);
seats[i] = new Couch("Couch " + i);
}
for (int i = 0; i < NUM_ITEMS; i++) {
user.sitOn(seats[i]);
seats[i].place();
user.open(openables[i]);
openables[i].place();
System.out.println(); // for readability purposes
}
}
} |
Output:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| Jack Daniels takes a seat on Couch 0
Couch 0 is being sat on.
Placed Couch 0 somehere
Jack Daniels opens Closet 0
Opened Closet 0
Placed Closet 0 somehere
Jack Daniels takes a seat on Couch 1
Couch 1 is being sat on.
Placed Couch 1 somehere
Jack Daniels opens Closet 1
Opened Closet 1
Placed Closet 1 somehere
Jack Daniels takes a seat on Couch 2
Couch 2 is being sat on.
Placed Couch 2 somehere
Jack Daniels opens Closet 2
Opened Closet 2
Placed Closet 2 somehere |
Let op de 2 arrays in de main-methode: die maken het grootste verschil van alles, omdat ze ervoor zorgen dat ik de arrays van het type kan declareren die de operaties kunnen uitvoeren (OpenableFurnitureItem die geopend kan worden en Seat waar op gezeten kan worden) die je wil hebben.