8

I have TopicBusiness.class and PostBusiness.class. I have no problem with deciding into which class methods such as addPostToDatabase() or getAllPostsFromDatabase() should go. But what about getAllPostsFromTopic(TopicEntity topic) or getNumberOfPostsInTopic(TopicEntity topic)?

Should the parameter be the deciding factor? So when the method takes TopicEntity as parameter it should belong to TopicBusiness.class? I am quite puzzled by this.

EDIT:

Some more info as requested. TopicBusiness.class and PostBusiness.class are classes holding all the business logic of the application concerning topics and posts respectively - that is fetching the data from database and/or performing some operations on them.

TopicEntity is data (in this case representing single topic) fetched from database. getAllPostFromTopic(TopicEntity topic) gets all posts from database that belong to particular topic, while getNumberOfPostsInTopic(TopicEntity topic) performs database query and returns the number of posts that topic passed as parameter consists of.

4
  • 2
    This depends on some factors you did not tell us so far. For example, what is the purpose/responsibilty of each of the 3 classes you mentioned in your post, and what is the purpose of thw 2 methods? Currently it looks like the 2 methods could be part of the TopicEntity class, but if that is a good decision depends on the missing information.
    – Doc Brown
    Commented Oct 18, 2013 at 16:13
  • I updated my question to provided more detail.
    – Eleeist
    Commented Oct 18, 2013 at 16:21
  • do you have unit tests for these classes, and/or for API they provide to objects using these? With unit tests, you could simply try both approaches and decide which one sticks better
    – gnat
    Commented Oct 18, 2013 at 16:30
  • Is there any reason why TopicEntity cannot contain that 2 methods as members itself? And what about database context - at which level is the db context available, and at which not?
    – Doc Brown
    Commented Oct 19, 2013 at 9:49

4 Answers 4

3

As a Topic can have multiple Posts, the TopicEntity.class should know what and how many PostEntitys it has, so Topics could have a getPosts() method instead of using another method which uses TopicEntity as parameter.

However if you need such a method for special purposes I'd say:

The method belongs to that business class which the result is belonging to.

On the concrete example this means:

getAllPostsFromTopic(TopicEntity topic) gets PostEntities, and getNumberOfPostsInTopic(TopicEntity topic) gets information about a subset of Posts, so both clearly belong to PostBusiness.class.

This is also intended by the choise of the methods names:

getAllPostsWhichAreOf(predicate)

getNumberOfPostsWhichAreOf(predicate)

2
  • 2
    Your answer addresses the specifics of the question but misses the general question that still needs to be answered. How would the OP go about deciding those things?
    – user53019
    Commented Oct 18, 2013 at 17:51
  • 1
    I thought this was clear by the secound paragraph: the method belongs to that class which the result is belonging to. But I overwork my answer to clarify that.
    – abto
    Commented Oct 19, 2013 at 9:22
3

These isn't an answer, but is too long for a comment.

At first sight, it looks like you've run into the multiple dispatch problem.

In non-object-oriented languages, you have functions and procedures, each of which can have multiple parameters. There is no "this object" because there are no objects.

In OOP as implemented in C++, Java etc, classes have methods. Excluding static methods, when you call a method, you specify the object that you're calling it for. The object is really a parameter, like the others - writing it before the method name and dot instead of within parentheses doesn't change that. However, it's specified in a special way because it has special properties...

  1. It's often implicit within the method. You don't include a this parameter in the method signature, and you don't have to use this (or any other name) to reference the object.

  2. This one special parameter is used for "dispatch" - to decide which implementation of the method to use in late-binding calls.

This approach is called "single dispatch" because there is one special parameter which is used for the dispatch decision. There is also something called "multiple dispatch" where the dispatch decision can be based on any/all parameters.

EDIT - sorry, I wrote "multiple inheritance" below earlier, that's a different thing.

With multiple dispatch, you don't need to nominate one particular parameter to be special - at least not for dispatch. All parameters are "special" in that way, therefore none of them are special. You might still want a special "this object" for reasons of abstraction, but you don't need it just to support calling.

Multiple dispatch is rare to non-existent in OOP, but it exists in a few languages - I believe it's in Common Lisp, though I don't know for sure. The way I know about it is more for domain-specific languages such as treecc - actually I've written a tool based on treecc, but designed for working with C++.

Without multiple dispatch as a language feature, you have two issues...

  1. Which parameter to make into the special "this object" parameter for a method.
  2. How to implement multiple dispatch as a design pattern where needed.

The first issue is all about abstractions, and doesn't always have a good answer. In C++, it's commonly pointed out that sometimes using non-member functions can even improve encapsulation. Maybe your method shouldn't be a method at all?

I'd add that just because you're defining a function separate from one class doesn't mean you can't put it in another class - you could define a third class with "tools" that manipulate objects of the other two class types. There's a common claim in OOP that "the shape draws itself", due to the teaching example, but it's wrong to infer that a class must always encapsulate the data it works with. It encapsulates the implementation of its own abstraction, but the nail is a separate object - not a part of the hammer implementation. Some kinds of objects are designed to work together - to interact via a shared interface - and are therefore somewhat coupled. That's not a goal to seek, but it's an unavoidable fact of life, and you get better encapsulation by having hammer and nail as separate classes than by having one combined hammer-and-nails class.

The other issue is how to handle a multiple-dispatch decision. There are lots of options because it is, after all, just a run-time decision you're making - the compiler didn't handle it for you so you have to code it yourself. However, for maintainability, a particularly good solution is "redispatch" - using a sequence of single-dispatch decisions to implement multiple dispatch. Each method calls another method (with a different parameter taken as special) until the dispatch is fully resolved. I don't have a good link for this. I got the term from the Ada95 reference manual, but Ada wrongly claims to support multiple dispatch just because redispatch is possible (a design pattern is not a built-in language feature).

This is a heavy-weight pattern - there's a fair amount of code to write. But it normally gives good error messages. Not perfect - it can fail to see a problem if you have non-abstract base classes - but it's still a lot better than e.g. a switch.

One place that redispatch is used is in the visitor pattern. Some people say that the visitor pattern is only needed because OOP languages lack multiple dispatch. I'm not entirely convinced. Certainly, a big part of the visitor is doing redispatch to solve the double-dispatch (two special parameters) case of multiple dispatch, but there's also an abstraction with clear roles - visitor and visitee - and other details that are separate from multiple dispatch.

1

I wouldn't say parameter, but basically yes.

Number of posts is a property of a topic, as are the posts in the topic.

Consider the NNTP References header for a real world example. A post (message) knows about it's direct parents. But it doesn't know about it's siblings or children. This is of course mandated in the case of NNTP because it is a distributed system, and in a non-distributed system you could in theory make each post have a reference to every other post in the topic. But doing so doesn't actually help because it doesn't help with the model, which is typically a tree.

To decide where things go, model what they are logically a part of.

1

The other answers here are good. I think it's worth mentioning the GRASP pattern called Information Expert. The GRASP patterns were designed for teaching good OO practices in a university. In brief, the Information Expert pattern says that the class that has the most information about an activity should own that activity.

In this case, I would think that TopicBusiness knows more about topics than PostBusiness, so it should contain the behavior.

1
  • I've never heard of GRASP before - interesting.
    – user8709
    Commented Oct 19, 2013 at 18:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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