So I have a List of Component.java, right? Inside of this list, I want to store a few types of classes all of which extends the Component.java class. See, that part I can do just fine. At present, I’m storing Wire.java’s and Pipe.java’s.
However, when it comes to accessing the different types inside of the list, I’m faced with a dilemma.
First I tried it like this: for (Wire w : component_list)
However, it can’t iterate over only a single type of component inside of the list; it’s looking for Wires when the iterator only knows to return Components.
Seeing this, I tried:
for (Component c : component_list) {
if (c.equals(Wire.class)) {
Wire w = (Wire) c;
}
}
However, I’m not sure that it’s working properly. I’m wondering, is the second option possible?
Depending on what you’re doing with your custom components when you’re iterating over them an alternative is to have your classes implement an interface with the operations that you want to perform on them, i.e.
interface MyCustomInterface {
void whatever();
}
class MyCustomComponent extends Component implements MyCustomInterface {
void whatever() { ... }
}
...
List<MyCustomInterface> list = ...
for( MyCustomInterface c : list ) {
c.whatever();
}
The interface is a sort of adaptor pattern, meaning you get more readable code and no nasty casting.
You could also insert an extra layer with an abstract base class if required.
That’s actually a very good tip. However, isn’t it sort of misleading when you’re going through the interfaces for each component type rather than the actual object itself?
Also, I’ve abandoned that method of components for now and instead have a basic VoxelGroup class that has an enum of GroupTypes to determine how it should behave (Another class entirely). The list of voxels from before is non-existant
With that in mind, would your interface method still work properly? Or should I change my architecture slightly to accomodate?
And the idea of an abstract base class; would that replace the VoxelGroup class, and then I would create multiple classes for different types of groups, all of which would use an interface for commonly needed methods - that about sum it up?
It’s an example of separation of concerns: the code that is doing the iterating and invoking the method on the interface doesn’t care what the actual objects are - this is of polymorphism.
Therefore that code loop is now completely independent of any specifics about your classes that implement that interface. Thus:
there are no dependencies between that bit of code and any of your component classes: simpler, cleaner code that is more maintainable.
you can add (or delete) components without having to change that code.
you can change the behaviour of those components and that code will still work.
[quote]Also, I’ve abandoned that method of components for now and instead have a basic VoxelGroup class that has an enum of GroupTypes to determine how it should behave (Another class entirely). The list of voxels from before is non-existant
With that in mind, would your interface method still work properly? Or should I change my architecture slightly to accomodate?
[/quote]
Probably not if I understand your new design. I would imagine you would switch on the enum to implement different behaviour for each voxel group.
The pattern I suggested is a good way of doing things for the reasons listed above but sometimes it’s overkill, the enum approach may well be simpler in this case.
Pretty much yes. The idea of the abstract base class is that it’s a template implementation that would implement the interface with default behaviour, and concrete classes would extend (or override) that behaviour. e.g.
interface Component {
render();
update( long time );
}
abstract class AbstractComponent implements Component {
protected long lastUpdate;
render {
// do nowt
}
update( long time ) {
lastUpdate = time;
}
}
class Wire extends AbstractComponent {
render {
...
}
update( long time ) {
super();
...
}
}
...
Again, it’s a useful and fairly common practice, but whether it applies to your situation only you can tell