UML sequence calls between entities without knowing about each other - oop

Let's say we have a tiger who hunts for his prey, standing on a field. When the tiger starts hunting, he asks the field what is standing on that currently. After that, the tiger starts to eat them one by one. If it eats a hyena, then it bites him which in turn the tiger let the hyena go. If the tiger hunted more than two hyenas at once, it dies from their bites. If the tiger eats an antelop, the antelop dies.
I created a sequence, but as far as I know, it breaks the OOP principles. What should I change to fulfill the principles? How can the Hyena response for the eating method without the tiger let the hyena know about this?

Indeed: It’s not up to the tiger to tell the hyena to bite it, nor the hyena to decide for the tiger to let it go. The tiger should not even know about the internals of the hyena (principle of the least knowledge).
You need to decouple these two classes. A first step would be to hide the internals, abstracting the hunter and the prey into more general beings.
The next step could be to transfer the responsibility of the interaction between the involved beings in a field to a mediator that would take charge of the choreography of the exchanges, using only the known interface of the beings, which tiger and hyena specialize.

Related

Characteristics of bad object oriented design

I am reading about object oriented design principles. I came across the characteristics of a bad design.
It is hard to change because every change affects too many other
parts of the system. (Rigidity)
When you make a change, unexpected parts of the system break.
(Fragility)
It is hard to reuse in another application because it cannot be
disentangled from the current application. (Immobility)
I am able to understand the first two but the third one is little difficult for me to understand.
Is it about extracting common features of related classes in a Base class, making methods from the code which is repetitive ? But it says hard to reuse in another Application. Usually we write context specific code and Over-engineering is not a good idea, we have good principles like YAGNI (You ain't gonna need it) I find these ideas little contradicting.
Please provide your valuable thoughts for this.
Mobility example:
Assume the following classes:
Animal
Canine
Dog
As you would expect, Canine extends Animal and Dog extends Canine.
One way to poorly design Animal is to give it a method talk() which prints out bark. Perhaps, the original intent of this application was for dogs only and therefore the talk method barking was fine. But reusing this in another code base would lead to issues.
Say we want to extend Animal and create Bird. Birds don't bark :)
It's hard to image that someone would do this. But it happens all of the time. Base classes aren't abstracted out which leads to misplaced code making it difficult to correct/reuse.
One could argue that the Bird class could override the talk method. That would work, however, another developer extending Animal for yet another reason may forget to override that method... etc.
I know this isn't the best example, but it demonstrates the problem.

How does the single responsibility principle relate to cats and dogs?

From Wikipedia:
Martin defines a responsibility as a reason to change, and concludes
that a class or module should have one, and only one, reason to
change.
However, every time you see an object-oriented analogy, they refer to cats and dogs, and how they have attributes and methods like so:
class Dog extends Animal{
public breed;
public dogYears;
public function bark();
public function move();
public function sleep();
etc, etc...
}
I find a better way to implement bark, so I do that. I see that the dog doesn't move properly, so I fix that. Etc etc. There are more than one reason to change the class.
So, why is this analogy always used? What would be a better way to adhere to the SRP?
Don't take it so literally.
In your example, Dog is responsible for performing real life "dog actions", such as barking, moving and sleeping. You can see this as one responsability. The SRP states that Dog should not be responsible for perming any non-dog actions, such as logging his movements.
This prevents you from having to change the Dog class if you decide to change the logging mechanism - because performing "dog actions" and logging are two completely different responsibilities.

Can Liskov Substitution Principle be applied (php example)?

"Subtypes must be substitutable for their base types"
Let's say I have a Bird class already, and:
class Parrot extends Bird {
public function Talk() {
echo 'Talk';
}
}
A Bird can't talk so I can't substitute a Parrot with a Bird.
This is just a basic example but usually the extended class can do much more then the base class. What am I missing?
The point is a parrot should act like a bird in all ways, so that someone who has a plan for dealing with birds in general won't be surprised by a parrot they run across. If the parrot happens to be able to talk as well, it doesn't matter, because their plan doesn't involve asking birds to talk.
For example, perhaps they just call $bird->fly() on every bird they get - the ability of a parrot to talk won't disrupt that activity, so their algorithm still works. But if you invent a sort of bird that can't fly (an ostrich, say), then you've violated the principle, and their general bird-handling algorithm no longer works on all sorts of birds.

Musing/open questions on OO philosophy

I'm going to use this opportunity to put down a number of related but different thoughts on object-oriented philosophy, as a sort of request for comments. If the admins see fit to close, I may make it a blog post instead. But I am asking questions, so I think it's a suitable community wiki.
Suppose I have an abstract class Bird. Supposing that we're taking a fairly typical OO philosophy here, Bird is an object that is capable of maintaining and changing state. The obvious example of a state for this simple model is whether or not our Bird is flying or not.
So, Bird has a method fly().
Or does it? I've seen this very simple example given in introductory books, and in my opinion, it's subtly misleading. If you're maintaining state, you don't need to tell an object to continue to be in a given state; it just is. That's what an object does. So really, you want Bird to have a method takeoff().
Suppose at some point we created our Bird object from another class, Egg. At some point, we might call a method Egg.hatch() which has the return type Bird. Assuming we're coding to an interface, Egg knows what type of bird it's an egg from, and the returned instance from hatch() knows what type of bird it is also. But we can't really say that there's anything in common between an Egg and a Bird that hatches from it. are we really saying that we want specific implementations of these classes to have a reference to an instance of some sort of BirdArchetype that represents the characteristics of all instances of that species, so that both Egg and Bird know their own kind, independently but consistently? Is there any well-known pattern for this kind of relationship?
Whose responsibility is it to ensure that the Egg changes state so that it's no longer capable of hatching again, or doing most of the other things that eggs normally do?
Philosophically, do we want to introduce the concept of a breakable object? Perhaps Egg should be coded so that it throws an exception if you try to do any of the things that change its state more than once. It's up to the calling code to keep track of the client object's lifecycle.
What else can we do with an egg? Perhaps we could cook it. If it were me, I'd code this so that calling cook() on an egg 'breaks' the Egg instance and returns an instance of a new object, FriedEgg. How is this different to telling a Bird to takeoff()? It's absurd to suggest that taking off makes it a fundamentally different bird. Yet the reasoning is the same; a bird that's flying (usually) can't do most of the other things that birds do, because it's busy. Arguably then, Bird is breakable as while it's in the flying state, calling some of its other methods won't work.
I suppose the only real distinction here is that the Bird can become un-broken. Is the concept of thermodynamic reversibility really that crucial to programming very simple models like this?
This is why I don't particularly care for modeling the real world and using that to explain/define OO philosophy.
Unless you're building a simulator (in which the answers to these questions become immediately obvious when one looks at the simulator context) it's far too easy to go off into the weeds and confuse yourself.
Perhaps having mutating state in an object is all wrong ;-)
Shouldn't Bird.takeoff() return a FlyingBird which can land()? (It clearly doesn't make sense for a bird which is not flying to land.)
Similarly, for an egg:
egg = Egg()
incubatedEgg = egg.incubate()
bird = incubatedEgg.hatch()
However, the return type of an operation might not always be limited to one value. For instance, during incubating the embryo could die.
egg = Egg()
egg.incubate() ->
if "still alive" (aliveEgg) ->
aliveEgg.hatch()
else "died in incubation" (deadEgg) ->
deadEgg.discard()
Happy philosophizing :-)
"Fly" reasonably means "begin flying!" (I would say it's used more often that way in natural speech). You don't have to interpret it to mean "sustain flight!" That's why we reasonably use "fly" and "land" (in natural english) as antonyms. (Evidence for the skeptical)
You're assuming the egg is created ex nihilo in your model. That's not really a reasonable assumption. The bird came from an egg, but the egg came from a bird. Assuming a reasonable purpose for modelling an egg, it's to model the time-delay procreation of bird species. That means the baby bird is formed by the sexual reproduction of two other birds. The vehicle of generation of the baby bird is the egg. The egg doesn't need to know what kind of bird is in it; that bird was created by the parents and wrapped in a generic egg (that perhaps has variable properties based on the mother.
In other words, your model isn't really well-formed with regard to this question.
It's the egg's responsibility to see that it doesn't hatch again (a check in the hatch function). See the discussion of "imperatives" below.
The concept of "breakable" is probably superfluous to your model. Are you concerned with the egg's breakability, or it's hatchability? If the breaking is a significant part of the data you are trying to model (for example, if anything in your model essentially depends upon the brokenness of the egg, then model it. Either way, hatching doesn't happen when the egg breaks, it happens when the egg hatches. One of the consequences of hatching is breaking, not the other way around.
The reason egg.cook() seems wrong is because it is. Verb methods should take the object as the subject. Your statement "egg.cook()" is telling the egg to cook, which is rarely how we intend to use the verb "cook" in commands with respect to eggs. You probably really want a chef.cook(food) -- where the "food" arg is anything that derives from food (or better yet, has a Role (a la Moose) "isCookable".
Remember, programming languages are imperative languages; interrogation, exhortation, and other "natural language" functions are inherently misplaced in programming languages, even if we achieve some version of it through commands (we emulate interrogation through commands; "TELL ME YOUR STATE!" is the imperative interpretation of the interrogative "What's your state?")
A good program removes as much information as possible from it's models while meeting all functional specifications. That is, you have a specification (preferably in the form of a test suite). Meaningless information is information that isn't necessary to pass any of the tests. So, you implement one feature at a time, introducing the cookability of eggs when you have a test that quantifies that property via specification (again, read: tests). If you implement breakability of objects and realize that you can accomplish the same tests without it, you improve the program by removing it. Now, a really clever programmer is able to build his models in such a way as that they are extensible -- that is, that new properties can be added easily as new requirement specifications are produced.
Note also, it is possible to have a bad specification. If you can't tell whether something is superfluous or not, the specs (read: tests) are either incorrect or incomplete with respect to that aspect of the program.
Seems more like an issue of naming. For example, in java you might query the bird's state as "getFly()", where you call it "fly()" as python would. Here, you're telling it to take off like you're changing the state of the bird, which is a little ambiguous to the reader of the code.
In the case of the Egg, I don't see any problem with the species of bird the egg handles as being part of the egg. As for who handles whether the egg is hatched, you could just keep a reference inside the egg to the bird that's hatched. An egg physically hatches, so it's up to me to see if it's hatched, so I don't stick an egg shell in an incubator for months expecting a chicken to pop out. In my opinion, it's up to the calling code to know who has hatched. If an egg hatches a bird, it's okay to keep a reference to that bird inside the egg if that helps keep your program organized. I would think it would be a convenience to anyone who uses that class.
There's no reason why you can't make an egg also be in a fried state, where any attempts to hatch it fail.
As to the absurdity of a different object for a bird in flight being a different bird than a grounded one, that's hard to justify. We may reason in our minds that it's the same bird, but in respect to object-oriented programming, we could certainly make them different objects if that meets the needs of the program. Is a bird more like an egg or a plane?
As to your Bird being breakable while it's in flight, is that the bird's fault? If my dog were in it's kennel, would it be broken if I told it to go fetch a ball?
Whose responsibility is it to ensure that the Egg changes state so that it's no longer capable of hatching again, or doing most of the other things that eggs normally do?
This depends on whether you want to keep around the egg remains in your model or consider the egg gone.
If the former, the hatch() method sets a private hatched flag to true and any of the egg's methods which depend on it being un-hatched (including hatch() itself) check that flag and fail (whether the failure is via return code or a raised exception, depends). The latter, might be doable with certain designs but don't really see any need to.
Or does it? I've seen this very simple example given in introductory books, and in my opinion, it's subtly misleading. If you're maintaining state, you don't need to tell an object to continue to be in a given state; it just is. That's what an object does. So really, you want Bird to have a method takeoff().
I think that your problem here is with imprecise word usage, not with software development. The authors of the fly() solution are usng "fly" verb in a sense of "start flight", e.g. as a synonym of "takeoff". Whether that's a 100% valid English usage or not is above my pay grade as ESL developer, but I certainly agree that "takeoff" is a significantly less ambiguous method name.
... so that both Egg and Bird know their own kind, independently but consistently? Is there any well-known pattern for this kind of relationship?
I'm not sure if there's an official "pattern", but having an egg constructor (or factory if you go with factory) implemented in a generic "Bird" class pass the bird type to a new "Egg" object and vice versa having "Egg" object pass its bird type to the constructor (or factory) of "Bird" is very widely used.
What else can we do with an egg? Perhaps we could cook it. If it were me, I'd code this so that calling cook() on an egg 'breaks' the Egg instance and returns an instance of a new object, FriedEgg. How is this different to telling a Bird to takeoff()
As a commenter already pointed out, the above is an OO design problem - the egg doesn't cook itself. Therefore you can't implement "cook" method on the egg in isolation (though some "set status to cooked" method might be needed for your model, if for no other reason than make it unhatcheable. However, the FriedEgg thing needs to be constructed (if needed) by a Cook object's "cook_egg" method - which also calls "set status to cooked" on an egg.
I don't think this really comes under OO philosophy. In my opinion, you're mixing business logic with design patterns.
To address your concerns in general, if you have a method that changes the state of the object, which can cause another method to throw an exception based on this new (changed) state, it is desirable to have a state-inspection method so that you don't have to explicitly handle the exception each time.
In your case, let's say you did egg.fry() (on another note, an egg cannot fry itself. So maybe you need a Cook class that takes an egg as an argument to a fry method and returns a FriedEgg instance), and after that you did egg.hatch(). The second call must return an exception. Instead of forcing the user of your class to put that call in an explicit try...catch block, you should provide a state-inspection method; something like isFried() or isHatchable(). Then instead of:
try {
egg.hatch();
}
catch(UnhatchableException e) {
...
}
You have:
if(egg.isHatchable()) {
egg.hatch();
}
So it is the responsibility of the calling code to check and see what state the object is in, before it performs an operation that can potentially throw an exception.
Now assuming you had a Cook class and a method called fry and you did Cook.fry(egg) which returns a FriedEgg instance, what would happen if you call hatch() on it? Common sense would tell you that a fried egg cannot hatch anything!
In this case, you should have an Egg interface with LiveEgg (i.e., an egg that can hatch) and FriedEgg both implementing the Egg interface. The difference however, is in the implementation of the hatch() method in FriedEgg; it would have to throw an UnsupportedOperationException because you cannot hatch a fried egg.
The problem with modeling most real-world scenarios (like cars, animals etc.) is that sometimes they don't help in adequately explaining the relationships. This is due to the fact that OO concepts are pretty abstract.
Anyway, hope this helps.

Object oriented design, define relationship

I am getting really confused about OOD when designing relatively large system. Always, we talk about has-a relationship between two entities. My question is about which one owns the other?
when designing a parking lot, there are many parking space. Should the car has an data field called parking space, or should the parking space hold the car? or both?
in a library reservation system, I am assuming there is a class Library, a class Book, and a class User. Shall the user call checkout(book), or the book call checkout(user), or the library call checkout(book, user)?
It's been very confusing for me. Any comment/suggestion is welcomed.
Lily
It depends on the situation, and what you mean by "own".
In your first example there is a one-one relationship between a car and a parking space. From a database perspective you will have to make a judgement about which should "own" the other (which table 'owns' the foreign key). You would base this judgement on expected usage - for example - since a parking space is likely to remain fixed, but you have cars coming and going all the time, it might make more logical sense for the carpark to "own" the car. That's where your design skills come into play.
In the second example, it seems to me that a single book can only be checked out to one user at a time, and "checking out" is an action that occurs on a book. Therefore the correct solution is Book.checkout(user). Building on that, a user is likely to checkout more than one book at a time, so I would be inclined to do have a checkout method on Library, such that Library.checkout(Books[], user) called Book.checkout(user) in turn.
For #1, the parking space should keep a record of if it is occupied and if so, what car is in it. Otherwise to see if you could park somewhere, you would have to poll every car to see if they are in that spot.
My immediate thinking for #2 is that it should be Library.checkout(Book, User) such that you make a note that a User has checked out a specific book.
This is heavily dependent on what you're trying to do however, and you should design it in such a way that is easiest for the problem at hand.
Sometimes replicating the data in two places isn't a terrible idea as long as you keep it synchronized. For instance, if you need to know where a specific car is parked, you're going to end up wanting to keep track of that data in the Car class as well, otherwise you're going to have to poll every parking spot to know if that car is parked there.
In Object Oriented design the object can be considered an entity. At this point you may use the Entity relationship modelling to better understand who has to own what.
When you design your model you shouldn’t care how you are going to implement it. I mean you shouldn’t think who is going to own what because this is another process of the design that is when you are going to convert your model to objects (that can be data table, XML, C# object ,…. ) : only at this point against the relationship the entity got you can decide who has to own what(sometime even against the requirements as I’ll show you later).
At the design time you must focus just on the requirements you have. In the case of the car and car parking you should think about :
How many park car one can occupied ?
How many cars a park can host ?
What kind of answer has my system to answer ? EX: as user I want know where a car is parked against its car plate number (in this case the previous answer would be wrong because if you let the park own the car you should iterate through the park to get what car is on it)
As you can see it really depends by you business requirements especially when you have “one-to-one” relationship(as in this case).
So I can suggest you to have a look at “Entity relationship Modelling” and stick to its concept to better design you object model.
In this case undoubtedly parking space should hold a car(it's called aggregation), because the relationship between car and parking space isn't permanent(different cars can be parked in the same parking place in the same day)
In this case, I think, the user wants to get a book, so the GUI of this system must have some button(or smht else) that user has to click to reserve a book. So, user calls a method checkout(book) of the system(object Library represents it) to check if the book is free(or available). Then the system(Library) checks whether the book wasn't reserved earlier by other user, so it calls method Book.check() for all instances of this book. In such solution every user account in the system should have a list of reserved books which method Book.check() uses.
To think out of box, I don't think the examples you provided have a natural "has a" or "owns a" relationship, and there are more relationships than "has a" or "owns a". In my opinion, I'd like to use a loosely coupled relationship for your examples, in implementation perspective, I would use a map to describe and maintain this relationship, which means, for a parking lot and a car, I would put a map in the Parking class, and map its slots to cars, if we find a slot existing in the map, we know that slot is occupied, if not, it's a free slot, for me, it doesn't make much sense either saying car owns the slot or the slot owns the car; for the library example, the same thing, the book and its borrower are in a very loose relationship, I'd put a map in the Library class, and map the book to its borrower. And who's the guy really does the checkout action? it's either the library staff or the auto machine or simply the library, so we can have a library.checkout(user, books), and inside the method, put books and user into the map.
For the bonus, what is really a "has a" relationship scenario? not a man has a car, this is not really a "has a", even we have "has a" in the sentence (don't let the human language mislead you), this just means, inside the car's class, there is a String field called ownerName or ownerId, that's it. One example for a real "has a" relationship scenario is human has a heart or a car has an engine, which means, in the implementation, there is really a Heart class field inside the Human Class.
How beautiful the object oriented design is!