views:

57

answers:

3

I'm wondering whether an object asking a question to another object that indirectly holds it is "bad" design. For example...

Requirements: Character (an object) moves on a grid. When it tries to move to another spot, it needs to know whether that spot is already occupied by something that blocks it, or if that part of the grid is completely inaccessible. (Note that the character itself needs to know).

In the application, a state holds a tilemanager and a charactermanager. The tilemanager knows what tiles are accessible and which aren't. The charactermanager knows the characters' tile locations.

Would it be reasonable for the character to call a function from the state, say AuthorizeMovement, which determines whether movement is possible via its TileManager and CharacterManager, and returns true if so, false if not?

Is this violating any important principles, leading to trouble down the road?

Obviously this is generalized and stripped down to what is necessary to understand the problem.

+1  A: 

I don't see a problem. Good OO Design comes with many principles. But at its core you have the big 4: Encapsulation, Inheritance, Polymorphism, and Abstraction. In addition, you want high cohesion and low coupling. Meaning your objects/classes can fit anywhere and aren't tied to a particular implementation or class.

With that said, it sounds like you have used the above to encapsulated movement and characters abstract them into separate classes. So your Character class isn't modifying the board directly, which would be bad if it were.

As you gain a deeper understanding of your problem, you can always refactor you code to improve your design to take advantage of other principles.

Jason McCreary
+1 agreed, it's not necessarily bad. For example an observer asks the observed object (which holds a list of all observers) for its state after a state_changed notification. Just watch out for infinite loops/dead locks
Dave
+2  A: 

I'd suggest that it is likely a bad design, yes. The "red flag," so to speak, is the circular reference. You said:

... an object asking a question to another object that indirectly holds it

So, the "holding" object has a reference to the "held" object, and also in order to "ask a question" the "held" object will need a reference to the "holding" object.

That's makes a circular object dependency graph and is often a code smell.

It would seem some other class should have the responsibility of knowing about both the character and the TileManager and/or CharacterManager.

qstarin
He could simply use a weak reference. After all, I sincerely doubt that his Character can operate independently of the State, so in reality, there's a reference here anyway.
DeadMG
@qstrain see my comment on Jason McCreary's answer. I agree with You about the code smell in general but there are legitimate use cases as well.
Dave
I'm questioning the assumption that the Character should know anything at all about moving itself. The Character in this scenario doesn't have enough information to know if and where it can move, which would mean that if Character decides to move, or is told to move, other objects need to update their state as well. This seems overly complicated. Why not invert the situation and message the CharacterManager and/or TileManager to perform the move. Then one of those objects could tell the Character where it is. That seems much more natural to me as all the info flows in one direction.
qstarin
@DeadMG WeakReference is just an implementation detail of the .Net garbage collector. What I was driving at was the bi-directional flow of information in the design when neither direction was clearly a fit for an observer.@Dave I think the fact that you had to warn for watching against infinite loops and deadlocks hints towards excessive complexity.
qstarin
+1: Such circular references are harder to test as well. In this case though I imagine an extra class is unnecessary: CharacterManager can just ask Character where it wants to move to and pass in anything required to make that decision.
CurtainDog
@qstarin: All decent reference count solutions, including the Java GC and C++'s std::shared_ptr, have weak references. And I'm not sure why Dave warned about infinite loops/deadlocks, I've never heard of observer pattern that caused such a thing.
DeadMG
A: 

It's not against any OOP principle. The details of the call are totally abstracted and you depend on the State object anyway. How on earth else would you possibly implement this function?

Abstraction and principles are useful tools. But you shouldn't depend on them to qualify your code as good. Not every abstraction or every principle is good for every scenario or every possible implementation. They're guidelines, not rules. If you can't quickly see an alternative implementation, use this one and then come back to it.

DeadMG