3

I'm working on a Java-based cellular automata-like implementation (not sure it technically is, given what follows) in which the individual cells may have different types that encapsulate different data and CA rules. There may be a large number of types, and I want to be able to dynamically plug in new ones without having to maintain other code.

All cell types derive from a common base class. Each cell's update() method is called exactly once per frame of the simulation:

public abstract class Cell
{
    public abstract void update(Cell[] neighbors);
}

This works fine when the CA rules only need the data of the cell in question, e.g.:

public class CellTypeA extends Cell
{
    public int Data = 0;

    @Override
    public void update(Cell[] neighbors)
    {
        Data++;
    }
}

However, I have some simulation rules that require the cell to query adjacent neighbor cells for data, but only if they are of a type that has said data. There is a strong temptation to use the instanceof operator to accomplish this:

public class CellTypeB extends Cell
{
    public boolean State = false;

    private void update(Cell[] neighbors)
    {
        for (Cell c : neighbors)
        {
            if (c instanceof CellTypeA)
            {
                State = (((CellTypeA)c).getData() > 10);
            }
        } 
    }
}

I'd prefer to avoid the smelly instanceof if possible. I also can't just promote getData() to the superclass to achieve polymorphism, as the actual data structure of these cells will be somewhat more complex and varied. I've been reading about the GoF Visitor pattern to solve instanceof abuse, but I can't seem to figure out how to apply it to this problem. Thoughts on how to do this, or on other ways to approach the problem?

Thanks! Steve

Stephen Carlson
  • 276
  • 1
  • 9
  • Seems to me the interaction isn't part of either cell. Perhaps put it in another separate class, and pass all pairs of (neighbouring) cells to that? – sje397 Sep 27 '14 at 03:27
  • I see what you're saying about the interaction not really belonging to either cell, but if were to do that, wouldn't I just end up using instanceof in a huge switch statement to define all the interaction permutations? And wouldn't an implementing client have to modify or extend this class to define new interactions? Or am I interpreting you incorrectly? – Stephen Carlson Sep 27 '14 at 03:36
  • I'd write a separate class for the code in each case of the switch, and put them in a collection. Then, I'd have some kind of filter function on each of these that lets you specify which cell types the interaction applies to. It's not exactly escaping your problem but it'd be fairly clean. This might help: http://stackoverflow.com/questions/2722343/java-select-from-collection-only-elements-of-provided-type – sje397 Sep 27 '14 at 03:41
  • Another thing to note is that if you have method `operate(Cell c)` and `operate(CellSubclass s)` on a class, and you call `operate(x)`, java will take the method with the most derived type that matches. – sje397 Sep 27 '14 at 03:55
  • Thanks, I forgot about that! Might prove very useful in making the visitor approach work. – Stephen Carlson Sep 27 '14 at 03:58
  • Actually, it depends on the type of ref you pass in, so might not help :/ – sje397 Sep 27 '14 at 04:00
  • Yeah, you're right, not so helpful. :) – Stephen Carlson Sep 27 '14 at 04:05
  • 1
    I would probably keep a form of the instanceof check, perhaps hidden - and favoring Interfaces instead of concrete types. "More patterns" isn't necessarily better and the complexity vs any benefit has to be weighed. Moving the update out of each cell sounds like an approach to explore (mainly it allows different algorithms to be applied without altering the "dumb" cell data-object class), but is an orthogonal task. I'm generally not a fan of the Visitor Pattern and often prefer to manually handle "type discrimination" in situations like this. – user2864740 Sep 27 '14 at 04:14

1 Answers1

2

I played around, and couldn't figure out how you'd make the visitor pattern a) neatly deal with two items to visit and b) be pluggable like you required.

This works, but probably hides the instanceof inside Guava stuff:

import com.google.common.collect.Iterables;
import java.util.Arrays;

public class CellTypeB extends Cell
{
    public boolean State = false;

    @Override
    public void update(Cell[] neighbors) {
        Iterable<CellTypeA> onlyAs = Iterables.filter(Arrays.asList(neighbors), CellTypeA.class);
        for(CellTypeA a: onlyAs) {
            State = (a.getData() > 10);
        }   
    }   
}   

P.S. Did you mean to use |= when assigning a value to State in the loop?

sje397
  • 41,293
  • 8
  • 87
  • 103
  • Thanks! Whether or not I use Guava, this gives me a clear idea of how I could "hide" the instanceof per user2864740's comment above. – Stephen Carlson Sep 27 '14 at 07:22
  • 1
    And I did mean to use |=, but it was pretty arbitrary - it isn't representative of the actual operations being performed. – Stephen Carlson Sep 27 '14 at 08:17