OOP: Which class should own a method? [closed]
Asked Answered
R

11

34

I’m having trouble understanding how classes relate to their methods. Is a method something that the object does, or something that’s done to it? Or is this a different concept entirely?

Specifically, in a library’s software system, should the borrow() method belong to the class representing the library patron, or the class representing the item that the patron is borrowing? My intuition is that it should read like patron.borrow(copy), like English sentence structure, subject.verb(object); but my instructor says that’s Wrong, and I don’t understand why he would have borrow() belong to the Copy class (and he doesn’t really explain things too well). I’m not looking for justification, but can someone just explain the proper relationship?

Edit: This question was closed as “off topic”. I don’t understand. Are software design questions not appropriate for this site?

Rosmunda answered 26/4, 2012 at 5:47 Comment(6)
He wants it to be library.loan(patron, copy) maybe? There are a lot of designs that would work. Why don't you ask him if you don't understand?Gilbye
Frungi this is the concept so it totally depends on you how you want to relate the classes.Epigynous
No no, he wants it to be copy.borrowCopy(account). And I already said he doesn’t explain things too well.Rosmunda
It's all arbitrary, this isn't an artifact of OOP at all, it's just advocating his view on the "right way" to do OOP. Objectively, there is no "right way," there are only viewpoints that are held by certain groups of people. As @6502 points out, OOP is not a set of high level rules, what you're talking about is Object Oriented Design, which is different than OOP.Mump
@KristopherMicinski You’re right, sorry, it’s for an OOD course. I’ve conflated OOD and OOP in my head.Rosmunda
In the case of C++, go with a free function.Firth
C
7

Some generic words first.

Software construction is not something which should be governed by English language rules or "beauty" or whatever, it's engineering discipline. Think of whether your design solves the problem, whether it will be maintainable, whether it will be testable, whether it will be possible to parallelize development and so on. If you want something more formalized take a look at the "On the Criteria To Be Used in Decomposing Systems into Modules" by D. L. Parnas.

As for your library example. Imagine you have a Copy outside of library, shoult it have borrow method then? How the borrowing is registered? Are you ok with either Copy or Patron classes responsible for data storage? It looks more appropriate to put borrow into a Library class. Responsibilities will be clearly divided, you wouldn't need to know much about borrowing to implement Copy and Patron and you wouldn't need much details about them to implement Library.

Clavicorn answered 26/4, 2012 at 7:35 Comment(0)
S
12

subjective :) but honestly, I'd go with the Information Expert Pattern and say something like

library.lend(item, patron)

The library contains the information about the items it has (perhaps in its catalog).
The library lends the item to the patron (which it knows because it registers them)

Not sure how your instructor sees this, but this is the level of 'abstraction' (software objects mimicking real world entities) that would make sense for your scenario.

Simplicity answered 26/4, 2012 at 5:56 Comment(4)
this will potentially make library class handle too much stuff that can be done in other classes.Spinnaker
@RayCheng True, but this seems more sensible than both my way, which would have the patron method setting properties on the book, and my instructor’s way.Rosmunda
@RayCheng: arguably, but then this is OO-land. I would prefer that the 'library-based' interactions between the item and the patron, be encapsulated within the Library ( Mediator Pattern - just to name-drop :) )Simplicity
@RayCheng: Perhaps the library could be composed of other objects that handle the different "other stuff" (not sure how this would work in practice though).Sebaceous
S
10

You should not confuse the idea of OOP with one specific incarnation like Java or C++.

This limit "methods are a property of the object" is not part of the OOP idea, but just of some implementations and as you discovered it doesn't scale well.

How many methods sould an "integer number" object have? What is more logical... myfile.write(myint) or myint.write(myfile)? There is really no good general answer to this. The idea of a method being part of a single object is a special case and sometimes the bending needed to fit the problem to this solution can become noticeable or even close to a showstopper. The answer is really totally acceptable only when a method has no parameters except the object being processed: single dispatch is a perfect answer only when there is a single type involved.

In other languages you have a separation between objects and methods, so for example you have the file object, the integer object and a method write(myfile, myint) that describes what to do when the operation is needed... and this method is neither part of the file nor of the integer.

Speechless answered 26/4, 2012 at 5:59 Comment(1)
You're the only that mentioned dispatch. Perhaps you should expand on why that's important when deciding where to put a method? This could be useful for the OP.Alterative
C
7

Some generic words first.

Software construction is not something which should be governed by English language rules or "beauty" or whatever, it's engineering discipline. Think of whether your design solves the problem, whether it will be maintainable, whether it will be testable, whether it will be possible to parallelize development and so on. If you want something more formalized take a look at the "On the Criteria To Be Used in Decomposing Systems into Modules" by D. L. Parnas.

As for your library example. Imagine you have a Copy outside of library, shoult it have borrow method then? How the borrowing is registered? Are you ok with either Copy or Patron classes responsible for data storage? It looks more appropriate to put borrow into a Library class. Responsibilities will be clearly divided, you wouldn't need to know much about borrowing to implement Copy and Patron and you wouldn't need much details about them to implement Library.

Clavicorn answered 26/4, 2012 at 7:35 Comment(0)
S
3

As @Ryan Fernandes said, the lend/borrow operation cannot be with either patron or book. It has to be with some class that knows about the status of all the books and patrons of the library. For e.g., are there pending reservations against a book? How many copies are available? Has this patron paid all the fees? Is he eligible for this book? So typically this should be in Library or a LibraryService class.

Sumikosumma answered 26/4, 2012 at 6:3 Comment(0)
G
3

Public methods exposed from a class are the tasks that can be performed on the entity. That way the class would only encapsulate its behavior.

For example: if i say

Computer.TurnOn()

The method will only work on the computer system.

instead if i say,

SomeOne.TurnonComputer()

The someone will now have the responsibility to turn on the computer(set related properties of computer), that means we are not meeting the concept of encapsulation and scattering the class's properties all over the place.

Glycolysis answered 26/4, 2012 at 6:17 Comment(0)
L
3

The point of OOP is to create polymorphic functions that, in each implementation, deal with a defined set of data which obey specific invariants.

It follows that a method which alters an object should be defined in the class of that object. It matters less where code that is purely functional lives, but it should probably live on the type of its input (if it takes a single input) or on its output.

In your example, if borrow alters data in copy, then it should live there. If, however, you model the loan status of a book by it being held in a particular collection (either in a patron, or in a collection for the library), it would make more sense to put borrow on the holder classes. That latter design, however, runs the risk that a copy could be in more than one collection, so you would want to put some information (and a corresponding method) on the copy as well.

Lilas answered 26/4, 2012 at 7:44 Comment(2)
In the OP's example, I would guess the method will alter data in both Patron and Library. So there should probably be two methods, one in each class: Library.lend(book, patron) and Patron.loan(book). lend will alter the necessary data in Libraryand call loanon Patron which will alter the necessary data in Patron.Alta
LOL, no, I missed that. Obviously my comment is redundant.Alta
P
1

Not pretty sure for the exact justification , but you can think it this way, IF multiple patients go and visit a doctor, its only the doctor who know when to call in the next patient, so the next method would be a part of Doctor's Responsibility, though its tempting to think that next should be the part of Patient's responsibility as he has to go next, someways when the library book is to be issued, it should be the responsibility of book genre rather patron as book(RESOURCE) knows when it will be free .

Pentheam answered 26/4, 2012 at 5:53 Comment(0)
B
1

Is a method something that the object does, or something that’s done to it? Or is this a different concept entirely?

Let me clear something about class and objects first. Class are generally used to a denote particular category. Like

  1. Cars not Ferrari, or Porsche
  2. Fruits not Banana, or Apple

So, it's Ferrari that is driven, and a banana that is eaten. Not their class

Its always an object that has properties and has behavior.

Even going to your case specifically.

borrow() method is an action/behavior done by a object of a person on an object of book whose records is kept by another object of the library system itself.

A good way to represent this in OO way for me would be like

libray.borrow(new book('book title'), new person('starx'));

Just for fun, What do you think about this

person starx = new person('starx');
book title1 = new book('title1');
library libraryname = new library('libraryname');
libraryname.addBook(title1);

if(starx.request(title1, libraryname)) {
     starx.take(library.lend(title1, starx));
}
Built answered 26/4, 2012 at 6:12 Comment(6)
I wasn’t asking about class vs object. I was asking to which class the method should belong. Like, should it be mouth.eat(banana) or banana(eat)?Rosmunda
@Frungi, That is what I am trying to explain. Please see the updateBuilt
a person should not borrow a copy of the book. what if all copies are out at the library? do you throw exception or return null for bookingId? copy.borrow(new person('startx')); is better.Spinnaker
Then I retract my complaint. =)Rosmunda
@RayCheng I imagine the patron would have the copy in hand when checking it out.Rosmunda
@Frungi, What do you think about the update?Built
H
0

I guess it can go either way. There is no hard and fast rule for it. The idea is the group functions logically that makes sense. To me, Patron#borrow(BookCopy) make same sense as BookCopy#borrow(Patron). Or you may have a class LibManager.borrow(BookCopy, Patron).

Heinrick answered 26/4, 2012 at 6:3 Comment(0)
H
0

Your instructor's right. Well, actually, he's wrong. I don't know.

My point is, for questions such as this, there are often no firm general answers one way or another. It largely comes down to what works best in your particular case. Go with whatever's easiest to code - it'll be the easiest to maintain. And, by "easiest to code", I suggest also taking into account the intended users of the classes (beyond just your Library, Copy and Person classes).

Hooded answered 26/4, 2012 at 6:4 Comment(0)
V
0

I was thinking about precisely that today. I came to this conclusion:

Whichever makes more sense in the appropriate context.

Valgus answered 26/4, 2012 at 8:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.