0

My students have a hard time assigning correct responsibilities and methods to classes. They get confused about which method suits which class better.

Suppose we have two classes, class A and class B. It may not be very clear if method m1() is best to belong to class A or to class B.

Any references or methods that help in this regard is extremely appreciated.

User 19826
  • 143
  • 5

1 Answers1

3

I'm not going to name a resource, partly because it might be my own work. But I can give a mini-lesson.

The question actually sounds like it comes from someone who is familiar with "procedural programming" in some way and wants to hammer the thinking mode from that into a completely different paradigm: OO programming.

Different paradigms require different ways of thinking and it can be difficult, even impossible for some, to switch paradigms. It took me a long time to switch to a deep understanding of OO after being completely immersed in procedural programming. I'm still a very weak functional programmer unless I get some helps like the concrete syntax of something like Standard ML.

In the procedural programming paradigm you consider a solution to be the result of carrying out a process. The process is carried out by one or more procedures (and/or functions). The "Way to Program" is one of writing complex procedures as some sort composition of simpler procedures. This seems to me to be the way of thinking that you (the OP) normally apply. If you try to force this way of thinking into OO it becomes very artificial. Hence the problem you face.

In OO programming you don't think of a program or a solution as a process, but as the interaction of independent entities (objects) that each have behaviors that can be invoked. The objects are self contained and present an interface to the larger program, perhaps defined by a class.

So, the way to think in OO is "what are the objects and how do they behave". Given a problem statement, think about the nouns, which normally represent "things" that can be objects. How do such "things" normally behave and how do they interact with other things with the same and different behaviors.

Complex "things" can be composed of simpler things (other objects defined by other classes), not just primitives of the language. It is a big step too learn to model the problem space as objects composed of and interacting with other objects.

Then the solution of the problem becomes something like a choreography getting the various objects to exhibit their inherent behaviors in a coherent way toward a goal.

If you can start to think that way or teach it to your students, then your question goes away. The "methods" represent the behaviors of the objects, so there is no notion of "distributing" them to classes.

Think of objects as "bundles of behavior", with the public methods defining that behavior. Avoid thinking of them as "bundles of values" that get operated on by the methods. The methods are primary, the fields are there to support those behaviors.

One aspect of the "bundles of behavior" idea is embodied in the "Tell, Don't Ask" principle. This means that most methods of an object tell it to do something, rather than ask it for information to be used elsewhere. This centralizes decision making (and mutation) in the object itself, rather than pushing it elsewhere in the program, which would make it harder to track. So, few methods should access information, and especially avoid accessing the values of fields.


One of my favorite examples of paradigm change is the Battle of Agincourt in which Henry V destroyed the French knighthood by changing the paradigm. He defeated and army of highly trained warriors (knights) with a peasant army (archers). The French had no way to reply.

But it took about a century before nobles were no longer trained as knights, with Henry VIII being the last fully trained king-knight. Old lessons die hard.

Buffy
  • 35,808
  • 10
  • 62
  • 115
  • 1
    Nice answer, of course. I think another aspect is that procedural programmers sometimes don't realize that there are intermediate objects that help in "process". Without identifying these immediates, it can be more difficult where to place the methods. In short, there are sometimes shorter-lived entities that should also be manifest as objects with responsibilities/capabilities and this is sometimes the answer of where functionality should go. Evaluate lifetime of state (both in objects and in local variables) to help identify missing objects. – Erik Eidt Nov 25 '21 at 01:24
  • 1
    Thank you for the answer. It is very helpful. I would appreciate if you could also provide a reference, even if it is your own (as you use a nickname here, I won't even know if it is your material or someone else!!) – User 19826 Nov 26 '21 at 06:59