When designing, we should ask ourselves what happens when we change something. And if we were to change, how much effort is required? how many places will have to change.
Continuing with the Game of life example. For our next set we want to set that a cell is alive at a certain location.

We could provide a x and y coordinates like so.

[code lang="java"]
public class World {

public void SetLivingAt(int x, int y) {
//...
}

public void IsAliveAt(int x, int y) {
//
}

}

[/code]

This appears like a resonable approach to take, which will then lead us to changing the LivingCell and the DeadCell to include this coordinates.

[code lang="java"]
public class LivingCell
private int x;
private int y;

public int X {
get { return x }
}

public int Y {
get { return y }
}
}
public class DeadCell
private int x;
private int y;

public int X {
get { return x }
}

public int Y {
get { return y }
}
}
[/code]

However this approach can lead to a few changes and it's because of the subtle duplication of knowledge. The world class is now aware of the implementation details of the living cell. Also in this particular code example, it has the symptoms of primitive obsession.

A solution to primitive obsession and lower the knowledge duplication is extracting that knowledge into an abstraction away from LivingCell and injecting that abstraction in.

[code lang="java"]
public class Location {
private int x;
private int y;

public int X {
get { return x }
}

public int Y {
get { return y }
}
}

public class World {

public void SetLivingAt(Location location) {
//...
}

public void IsAliveAt(Location location) {
//
}
}
public class LivingCell
private Location location;

public Location Location {
get { return location }
}
}
public class DeadCell
private Location location;

public Location Location {
get { return location }
}
}
[/code]

Now that the Location knowledge is extracted, if we wanted to change  where locations are calculated, say introducing a third variable, "z", we only have...excuse the pun... location to change.

Ced