3 ms·
The Law of Demeter isn't about data encapsulation. It's trying to solve the problem of tightly-coupled code methods. It is a close cousin of "Don't get data f
by dhimes 14y ago
The Law of Demeter isn't about data encapsulation. It's trying to solve the problem of tightly-coupled code methods. It is a close cousin of "Don't get data from objects and operate on them- ask the contain object to do the operation for you." The Law of Demeter says, "Don't call a method on an object that was returned by a method of a different object." When you do this you are creating a tightly-woven daisy-chain which will lead to inter-dependency hell should something change in the future. Instead, you should either (1) ask the object you are calling to call the other object for you, or (2) call the third object method directly, without relying on the intermediary to get it.
In other words, with objects X, Y and Z. Assume that X has Y. You want to run method fz on Z. Don't do:
Y.getZ().fz
Do do:
Y.runFz() // calls Z.fz
or instantiate a copy of Z in X and simply
Z.fz
The data encapsulation principle is also about keeping things loosely coupled. By passing data around as an object, the interested parties need to care far less about the details (that is, their signatures don't change EDIT:TYPO _as_ the code changes).
This is a really good thing to do in the "build early and try it" style of building projects as adding data (parameters) to the signature is relatively painless.
- nessus42 14y agoIf I understand you correctly about the Law of Demeter, and we were to use an `Id` object to represent an ID, then the following would be verboten: val id: Id = db.findUserBySsNumber(ssNumber) println("id=" + id.toString()) // Violates Demeter! Instead we should do something like val id: Id = db.findUserBySsNumber(ssNumber) println("id=" + db.idToString(id)) // Demeter is happy. Boy, it would be a lot easier if `id` were just a string to begin with! Also, now we're physically dependent on db's data structures (i.e., `Id`). If we were to want to move `db` to be on a server, we would have to share at least some of the server's code. If `id` were just a string, we would be less tightly coupled to `db`.
- dhimes 14y agoIf I knew what your code was trying to do I might be able to write to it directly. But these guidelines would suggest that if you are going to call methods on the id object, it's best, if possible, to put the methods in the id object itself.
- nessus42 14y ago> But these guidelines would suggest that if you are going to call methods on the id object, it's best, if possible, to put the methods in the id object itself. But that would violate the Law of Demeter, as I understand it: E.g., you shouldn't fetch an Id object from a Db object, and then call a method on the Id object. I.e., you should only talk directly to the Db object. Not that the Law of Demeter is necessarily the best way to do everything, but it has its merits in terms of decoupling. I'm not sure where the code snippet that I provided wasn't clear. It looks up someone by Social Security Number in a database and gets back an ID. It thens prints out the ID. I'm also not clear on just what you are asserting: That my understanding here of the Law of Demeter is incorrect? Or that I shouldn't be following The Law of Demeter here.
- dhimes 14y agoIf the code snippet returns a local ID object, then calling a method on the ID object doesn't violate the law of Demeter. It can be, in fact, the preferred method in the case that you don't have control over the db object. If your snippet doesn't return a local id object, then the violating portion should be idstring = db.findUserBySsNumber(ssNumber).toString(); println("id=" + idstring) A (perhaps) more clear illustration is when you go the other way with the data. Suppose you want to change the last name of the user. You would want to consider that id.setLastName('Himes') db.updateUser(id) may be preferable to db.findUserBySsNumber(ssNumber).updateLastName('Himes') The first case is more robust (but, of course, not infallibly so) to changes in the api for db when, for example, the api providers decide it's too dangerous to throw SSNs around. It's also more robust against changes in the content of id. These are the kinds of things that OO guidelines can protect against. The tradeoff is added overhead (data objects)-- which means more testing, debugging, etc.
- nessus42 14y agoI'm sorry for not being more clear. `db` is a service and the code snippet is client code. I'm not sure what you mean by a "local object" (unless you are referring to C++'s stack-allocated objects). `Id` is a class defined by the service. The service doesn't know anything about the client code.