-1

So I have this distributed game im working on(for some time now). A part of the world is considered a Chunk object. This object is composed of many other objects/components that are necessary and a part of the Chunk.

In order the clear up the Chunk object which has the responsibility of a smaller area of an infinite world. I Separated some code into their own classes with their own responsibilties. These "smaller" responsibilities inside the Chunk. Are still objects which help solve the single responsibility of a single Chunk.

I kind of had to break Law of Demeter in order to keep the Chunk class more "neat & tidy" by allowing access to important components of the Chunk object.

I've thought about this a lot and I simply can't come to a better solution. The Chunk has a single responsibility which is accomplished by 8 other objects which help solve the Chunk's responsibility. And in order to clear the Chunk object of some code. I instead allowed getting a ChunkBlockComponents which contain access to the objects which help solve other things which are a bit more secondary to the nature of the Chunk(but essential).

To give an example. One component in ChunkBlockComponents is a HeatGrid. Which handles heat inside the Chunk etc. One other(EntitySpaceGrid) contains information which positions are occupied etc.

Then the Chunk object is mainly for adding or removing entities. And if more than that need to be done. Which can't be done when adding something. Then accessing ChunkBlockComponents allows interacting with the right component. For instance, for NearestFinder for finding the nereast entity of a certain type. EntitySpaceGrid for finding out whether an entity itself can move to its new desired position etc..

In this case I am still thinking about moving some public methods into the Chunk object again. To follow Law of Demeter. But that would add a lot of small methods to the Chunk class etc.

The reason for more public methods than just adding and removing entities. Is because of entities being able to update themselves and getting access to the ChunkBlock they are within on each update. To allow them making accurate updates etc..

So I am also wondering. Are big classes always avoidable/bad?

1
  • I strongly agree that "breaking" the "Law" of Demeter is a good idea to cut down on massive APIs and massive repetitive drudge code.
    – user949300
    Jan 30 at 16:17

2 Answers 2

3

The issue is less about size, and more about complexity. If you consider something like a 'String' class, this could have a great many methods attached. For instance, in python strings have methods such as replace,startswith,endswith,strip,removesuffix and many more.

Generally I'd be more concerned about a class having lots of state (particularly mutable state) than lots of methods (particularly if those methods take few arguments).

In your example, it sounds like Chunk has a lot of state, and by forwarding requests to its component objects, you're essentially requiring it to reimplement all of those interfaces. This means that Chunk no longer has a single responsibility. We define responsibility as 'reason to change', and if you change the API of any of your subobjects (e.g. HeatGrid) you'll need to change Chunk to use the new API as well.

It's difficult to give concrete advice without a more detailed view of your architecture. But you could have Chunk be a primitive data-type (e.g. a set of coordinates) which is then passed to factory / repository objects which provide the underlying subobjects to clients that need them. For instance:

nearest_finder = NearestFinder.for_chunk(chunk_id)

This would let you change the API for each specific object freely.

3
  • "We define responsibility as 'reason to change'," - this description needs to die because it just makes things more confusing Jan 30 at 18:28
  • @whatisname Better yet, change the name "Single Responsibility Principle" to "Single Reason to Change Principle" or "Single Difficult Design Decision Principle"
    – user949300
    Jan 30 at 18:44
  • Wouldn't this "Multiton" pattern you describe create some sort of global state and make testing harder? I implemented a Multiton pattern as NearestFinder.getFor(chunkId) which then creates and stores the instanced statically or gets already created instance. Before I implemented this change. Chunk only had a method for getting a components object, which then allowed retrieving the correct component for instance NearestFinder.
    – Sammyy
    Feb 1 at 21:21
0

The problem does not lie in the number of lines of code within your class. I think the word always is not the right term.

But, as you know, there are principles and good practices that you can learn to write better code. For instance, the five design principles encompassed by the SOLID acronym are a very good place to start. You have often mentioned the term responsibility, so if the class have a single and well defined responsibility, I think you are coding in the right way.

Unfortunately you have not posted any snippets of your code or even just toy code, so it is a little bit difficult to give more detailed suggestions.

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.