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?

Frungi
  • 506
  • 5
  • 16
  • 3
    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? – Carl Norum Apr 26 '12 at 05:51
  • Frungi this is the concept so it totally depends on you how you want to relate the classes. – Shaikh Farooque Apr 26 '12 at 05:52
  • No no, he wants it to be `copy.borrowCopy(account)`. And I already said he doesn’t explain things too well. – Frungi Apr 26 '12 at 05:55
  • 2
    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. – Kristopher Micinski Apr 26 '12 at 06:10
  • @KristopherMicinski You’re right, sorry, it’s for an OOD course. I’ve conflated OOD and OOP in my head. – Frungi Apr 26 '12 at 06:14
  • In the case of C++, go with a free function. –  Apr 26 '12 at 11:59

11 Answers11

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.

Ryan Fernandes
  • 8,238
  • 7
  • 36
  • 53
  • 2
    this will potentially make library class handle too much stuff that can be done in other classes. – Ray Cheng Apr 26 '12 at 06:16
  • @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. – Frungi Apr 26 '12 at 06:24
  • @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 :) ) – Ryan Fernandes Apr 26 '12 at 06:25
  • @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). – George Duckett Apr 26 '12 at 09:48
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.

6502
  • 112,025
  • 15
  • 165
  • 265
  • 2
    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. – Luc Danton Apr 26 '12 at 07:05
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.

Konstantin Oznobihin
  • 5,234
  • 24
  • 31
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.

krishnakumarp
  • 8,967
  • 3
  • 49
  • 55
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.

neo
  • 425
  • 3
  • 11
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.

Marcin
  • 48,559
  • 18
  • 128
  • 201
  • 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 `Library`and call `loan`on `Patron` which will alter the necessary data in `Patron`. – KaptajnKold Apr 26 '12 at 09:12
  • LOL, no, I missed that. Obviously my comment is redundant. – KaptajnKold Apr 26 '12 at 11:55
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 .

Akash Yadav
  • 2,411
  • 20
  • 32
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));
}
Community
  • 1
  • 1
Starx
  • 77,474
  • 47
  • 185
  • 261
  • 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)`? – Frungi Apr 26 '12 at 06:18
  • @Frungi, That is what I am trying to explain. Please see the update – Starx Apr 26 '12 at 06:19
  • 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. – Ray Cheng Apr 26 '12 at 06:26
  • Then I retract my complaint. =) – Frungi Apr 26 '12 at 06:26
  • @RayCheng I imagine the patron would have the copy in hand when checking it out. – Frungi Apr 26 '12 at 06:27
  • @Frungi, What do you think about the update? – Starx Apr 26 '12 at 06:55
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).

Nishant
  • 54,584
  • 13
  • 112
  • 127
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).

Mac
  • 14,615
  • 9
  • 62
  • 80
0

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

Whichever makes more sense in the appropriate context.

Thomas
  • 3,321
  • 1
  • 21
  • 44