Search code examples
oopdata-structuresdesign-patternsstructure

Class structure or design pattern for a shared border between two cells


This is more of a "best practice" or "best approach" kind of question; I was able to solve the core Problem myself, but I wonder how a situation like this should best be resolved.

Imagine a 2-dimensional board with a grid of square cells. Each cell is an independent instance of a class.

This would be the Pseudocode:

class Board {
    int width;
    int height;
    Array cells;
}

class Cell {
    Board parent;
    int x;
    int y;
    int value;
}

(To make the example a bit more clear: Imagine this is a Sudoku puzzle, with each cell holding a value.)

Now, while each Cell is independent, some Cells share a border. Let's say that this border is also it's own class, since it can be configured separately (for example, one cell's top border might be of a different color, style or thickness).

Now, if I extend the Pseudocode to accomodate for this:

class Cell {
    ...
    Array borders;
}

class CellBorder {
    Cell parent;
    int direction; // 0=top, 1=right, 2=bottom, 3=left
    Style style; // thickness, style, color, etc.
}

My Question is: Clearly, two connected Cells share a Border - what's the best way to deal with something like this?

  • Where is the Border instance initially created? Inside the Cell? Outside the Cell, in the Board class?
  • How would two Cells share a Border? Do they each have a pointer to the same instance, or two separate instances that just copy each other?
  • What if a Cell is moved to a different position? Are all affected Borders reconstructed or existing instances swapped?
  • If I want to configure a specific Border, how do I select it? By picking Cell(x,y).rightBorder? Cell(x+1,y).leftBorder? Board.border(x,y,'right')? (Ideally it shouldn't matter, but perhaps there is some benefit to one method over the other)
  • Should Borders (and perhaps even Cells) be created in a factory?

My current solution, is to only have the "top" and "left" Borders in each Cell, while linking the "bottom" and "right" Border to the neighbors "top" and "left" Borders respectively.

But generally speaking, what would be a good and flexible approach here? Would the Border handling be relayed to the Board instead of the Cells? I'm sure this type of problem must be fairly common and has some best-practices or perhaps even a well-suited design pattern.


Solution

  • Disclaimer: since you are looking for good practices in the object-oriented world, my answers will be oriented toward domain-driven design, object thinking and immutability.

    Where is the Border instance initially created? Inside the Cell? Outside the Cell, in the Board class?

    It would advocate that a Cell to request an array of already constructed CellBorder when creating itself. Requesting every field for every border separately (each direction and style for each border) would clutter the Cell creation.

    How would two Cells share a Border? Do they each have a pointer to the same instance, or two separate instances that just copy each other?

    If CellBorder is immutable, it doesn't matter if some instances are shared by multiple cells or not. If CellBorder is mutable then prefer creation of new CellBorder for each Cell to avoid nasty side-effects if the Board (or any Cell) were to update some CellBorder.

    What if a Cell is moved to a different position? Are all affected Borders reconstructed or existing instances swapped?

    Then the Cell's coordinates are just changed. Which effect does it have on its borders ?

    If I want to configure a specific Border, how do I select it? By picking Cell(x,y).rightBorder? Cell(x+1,y).leftBorder? Board.border(x,y,'right')? (Ideally it shouldn't matter, but perhaps there is some benefit to one method over the other)

    If Cell can't exist without being in a Board, makes sure to encapsulate the array of Cell inside the Board and add some behavior to the Board to change an existing cell's border. Example method call could be board.ChangeBorder(x, y, newStyle)

    Should Borders (and perhaps even Cells) be created in a factory?

    They could be if you are hitting some performance issues when instanciating a Board with all of its Cell. In the case of a Sudoku (assuming 9x9) I don't think this should be needed.