Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I'm currently working on a small 2D game-engine in C++, but I am now facing a daemon - I suck at designing a 'system of classes' that actually works. There are a blockade in my mind that disables me from seeing where I should use a class and where I should not. I was reading an article about engine-design and it purposed to use a 'State' class to manage the state of different game entries (I was using an int).
It also suggested that all objects for the game (not io/video/sound etc) derive from either Renderable or NonRenderable classes. That's smart. I already know that that was a smart way of doing it - I mean, every object in Java is of baseclass Object right? Smart, I know that! How come I didn't do it that way? What do I have to read to really get into this mindset?
Another example. I'm taking this summer-course in Ruby (really simple) and we're supposed to design a camping site. Simple! So, a camping is a collection of 'plots' that each have a electrical-gauge to measure how much power the guest has consumed. My design was three classes, one for a Camping - that in turn used arrays of Guest and Plot classes. My teacher suggested that I use more classes. WTF(!) was my first thought, where, what classes? Everything was a class in my opinion - until I realized, maybe the gauge should be a class to? Right now the gauge was an Integer in the Plot class.
I want to learn how to come up with a object oriented solutions to my problems - not just how to make the most obvious stuff into classes!
Tips/books/articles/blogs?
I'm two years into a collage degree in CS and have been programming as a hobby for many years! I'm 'just' stuck - and it's preventing me from creating any larger piece of software!
My personal experience was learning Object Oriented Software Construction with Object Oriented Software Construction, 2nd Edition by Bertrand Meyer.
The book was invaluable to me at that time, and still remains the single book from which I've learnt most regarding OO programming and software construction in general.
Here are some of its strong points:
In Part A: The issues, a very good definition of software quality.
In Part B: The road to object orientation, a logical, step by step search for OO techniques in a way that makes the reader think the investigation is being done live, that is, as if there were still no known results. You'll probably acquire the mindset you're looking for from this part.
In Part C: Object oriented techniques, the technical core of the book, you'll make your knowledge solid and learn very useful techniques regarding Design by Contract, Inheritance, Genericity, etc.
Part D: OO methodology: Applying the method well is a more practical approach on design, which I also find very useful. See for example How to find the classes (22), which you can find online.
After these parts, more advanced topics come, such as Concurrency (30) or Databases (31).
Since the book uses the Eiffel language (designed by the author), this will put you in the right mindset and teach you to think. It will be easy to apply these ideas to other, more or less OO, programming languages.
Object-oriented
Object-oriented programming is about asking objects to do something: a deceptively difficult concept to correctly apply.
Goban
Consider a 2D game board, like for playing Go (called a goban).
Think first about the behaviour it requires to accomplish its task. This means listing the behaviour for an object rather than deciding on data the behaviours manipulate. For example a basic board might have the following behaviours:
Place a Go stone.
Remove a Go stone.
Remove all the stones.
For a computer version of Go, it is convenient to bring attention to specific areas:
Mark an intersection (e.g., triangle, number, letter, circle, square).
Remove a mark from a marked intersection.
Remove all the marks.
Notice that a goban does not need to provide a way to provide clients with a reference to the stone at a specific intersection. Instead, it can answer questions about its state. For example, a goban might answer the following questions:
Is there a black stone at a given intersection?
Is there a white stone at a given intersection?
Is there a mark at a given intersection?
It is not the responsibility of the goban to know the state of the game: that belongs to an instance of a Game (which has Rules). In real life, a goban is simply a stage for stones.
At this point, we could write an interface for a goban without knowing how the underlying implementation will work.
public interface Goban {
public void place( Stone stone, Point point );
public void removeStone( Point point );
public void removeStones();
public void place( Mark mark, Point point );
public void removeMark( Point point );
public void removeMarks();
public boolean hasWhiteStone( Point point );
public boolean hasBlackStone( Point point );
public boolean hasMark( Point point );
}
Notice how the board is cleanly separated from both Rules and Games. This makes the goban reusable for other games (involving stones and intersections). The goban could inherit from a generic interface (e.g., a Board interface), but this should suffice to explain one way to think in terms of objects.
Encapsulation
An implementation of the Goban interface does not expose its internal data. At this point, I could ask you to implement this interface, write unit tests, and send me the compiled class when you have finished.
I do not need to know what data structures you have used. I can use your implementation to play on (and depict) a Goban. This is a crucial point that many projects get wrong. Many, many projects code the following:
public class Person {
private HairColour hairColour = new HairColour( Colour.BROWN );
public Person() {
}
public HairColour getHairColour() {
return hairColour;
}
public void setHairColour( HairColour hairColour ) {
this.hairColour = hairColour;
}
}
This is ineffective encapsulation. Consider the case where Bob does not like to have his hair coloured pink. We can do the following:
public class HairTrickster {
public static void main( String args[] ) {
Person bob = new Person();
HairColour hc = bob.getHairColour();
hc.dye( Colour.PINK );
}
}
Bob has now had his hair coloured pink, and nothing could prevent it. There are ways to avoid this situation, but people do not do them. Instead, encapsulation is broken resulting in rigid, inflexible, bug-ridden, and unmaintainable systems.
One possible way to enforce encapsulation is by returning a clone of HairColour. The revised Person class now makes it difficult to change the hair colour to Pink.
public class Person {
private HairColour hairColour = new HairColour( Colour.BROWN );
public Person() {
}
public HairColour getHairColour() {
return hairColour.clone();
}
public void setHairColour( HairColour hairColour ) {
if( !hairColour.equals( Colour.PINK ) {
this.hairColour = hairColour;
}
}
}
Bob can sleep soundly, knowing he will not awake to a pink dye job.
It pays to remember: OO is not an end in itself. The point of OO is to make development and, especially, maintenance of code easier over the lifetime of the product. Beware of the "OO for OO's sake" mindset.
Head First Object-Oriented Analysis and Design
I love Head First Books because they are fun to read. They have exercises and puzzles to scratch your head. I've read this book and found it very good.
The book covers:
Use OO principles (encapsulation and delegation)
Open-Closed Principle (OCP)
The Single Responsibility Principle (SRP)
Design patterns, UML, Use cases etc.
There are a blockade in my mind that disables me from seeing where I should use a class and where I should not.
When it comes down to it classes are a way to separate complex systems into simple parts that interact with each other. Try to create classes where otherwise you would be repeating yourself.
Right now the gauge was an Integer in the Plot class.
Does the gauge need to be a class? What would the advantage of turning it into a class be? These are the sort of things you always need to ask yourself.
Game Engines are difficult to design. The separation of such a vaguely defined requirements is a complex process, read here: article on game engines
Design is iterative and you'll refactor several times, don't be surprised by this.
There's an essay in the book "ThoughtWorks Anthology" by Jeff Bay: "Object Calisthenics" in which he gives a set of rules for designing OOP sofware:
Use only one level of indentation per method
Don't use the else keyword
Wrap all primitives and strings
Use only one dot per line
Don't abbreviate
Keep all entities small
Don't use any classes with more than two instance variables
Use first-class collections
Don't use any getters/setters/properties
On the first look it may look too strict to follow all these rules. Keep in mind that even trying to write some code that coplies them will make you better OOP designer.
Just remember there is never 1 solution to a problem.
Turning everything into a class is also not the solution. Especially tiny things (like the gauge) might very well be an int or float member inside the plot class like you had.
My suggestion is that practice is a good teacher. Just keep on trying, and keep on reading. In time you'll be more and more fluent.
I probably learned most about object oriented software development from Craig LarmanĀ“s Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development.
In his approach, classes are derived in a systematic way from use cases:
Nouns in the use cases are mapped to classes,
verbs to methods and
adjectives to member variables.
This, of course, works better for notions in the problem domain than, say, GUI widgets. Nevertheless, starting with a description/use case of the program to be written helped me to find better abstractions than when I omitted that step.
For me OO didn't 'click' until I read a book about design patterns. If you're already comfortable with concepts like abstract classes, interfaces, etc that's only half the battle.
The next step is figuring out why you should prefer composition over inheritance, how to code to an interface and how to write your classes so that they are decoupled and well-encapsulated. Design patterns show you solutions to common OO problems and help you structure your code adhering to the above guidelines.
I can't recommend any particular books about C++ but the GOF book is the standard on Design Patterns (Java). I prefer books that talk about design patterns in a particular language so that you can get concrete code examples. Design Patterns In Ruby is pretty good, as is PHP: Objects, Patterns and Practice.
I get the feeling that your instructor doesn't particularly know what he's talking about. 'More classes' is pretty useless advice by itself.
One of the things which helped to get into OO mindset, along with the practices that earlier posts outlined has been, is to rewrite/improving the existing code you have written using OO principles.
For example :
a. In situations where there is a lot of if/else constructs then probably
you can think of having a class hierarchy to distribute the branch codes accordingly,
and to use polymorphism.
b. Any use of operators like (instanceof in Java) would indicate programming to
concrete types and you can think how the instanceof check can be get rid of.
c. Use "Law of Demeter" as a guideline and see whether the coupling between
classes is high
To an extent the practice of "Test Driven Development" also helped me
since it forces you to think in terms of interfaces/behavior to be exposed
by a class rather than just concentrating on how best solution to a problem
can be coded.
Maybe you will find Thinking in patterns by Bruce Eckel useful. You can download this book from his site for free (I can only post one link as a new member, so just click on the links there and you can find it). Although, the book is from 2003, maybe the ideas presented in this book will help you grow as a programmer in general.
Write a really huge piece of software, and throughout the process, the bigger it gets, the more extensiblity you'll need and the more good class design you'll need, thus next time you'll think ahead and make your class design good in the beginning...
A simple way to come up with a reasonable set of things which probably should be objects (and hence, classes): write down a problem description of your task, like:
On a camping site there are guests, and each guest has access to a few outlets. The
software should be able to manage the power consumed by each guest, so it should know the
outlets used by a guest and the power consumed through each outlet.
Now, create a list of all the nouns for a good idea of what classes (= kind of objects) are involved in your problem:
Camping Site
Guest
Outlet
Power
This is not necessarily a definitive list, but it's a good start.
Haha. I remember that point. The whole "how the hell does this oo thing work?". Just keep at it, at some point it just clicks. It really is like a lightbulb going on. One moment it doesn't really make sense and then a split second later you're coding everything up in classes.
Try downloading some of the open source tools you will likely end up using and read the code. It'll give you something to reference your code style against.
Peter Coad and Ed Yourdon wrote a book about it couple years ago. While not filled with new overhyped methdologies, this book provides good foundation for thinking in object style.
In my opinion, one of the the best books I've read for learning object oriented concepts is:
The Object-Oriented Thought Process
For me, this book really gets you thinking in an object oriented way (well, the clue's in the title! :) It's fairly language agnostic, containing some small code samples throughout the text in VB.NET, C# and Java and frequently references many "greats" in the world of OO analysis and design, like Grady Booch, Martin Fowler and others.
Since the book helps you to think in an object oriented way, it'll often take a specific example and show the differences between the OO way of approaching a problem and the procedural way. This can be a big help if you're coming from more or a procedural background. It also touches on things like UML to help explain and understand the design behind complete libraries of classes (e.g. frameworks) and the interaction between classes and also the design of rich class hierarchies using concepts such as aggregation and composition.
Related
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 12 years ago.
I am trying to understand the core of object oriented programming for php or actionscript proect. As far as I understand, we will have a Main class that control different elements of the project. For example, photoslider class, music control class..etc. I created instance of those classes inside my Main class and use their method or property to control those objects.
I have studied many OOP articles but most of them only talks about inheritance, encapsulation...etc I am not sure if I am right about this and I would appreciate if someone can explain more about it. Thanks!
Same question , i was asking when i were just starting my career but i understood Object Orientation as i progress in my career.
but for very basic startng point in oop.
1- think about object just try to relate your daily household things like ( your laptop, your ipad, your Mobile, your pet)
Step 2-
Try to relate objects like ( Your TV an your remote ) this gives you the basic idea how object should relate to each other.
Step 3-
Try to visulize how things compose to create a full feature like your Body compose of (Heart, Lungs and many other organs)
Step 4-
Try to think about object lifetime ( Like as a example a car enigne is less useful outside Car , so if car is a object than this object must contain a engine and when actual car object destroys engine is also destroyed)
Step 5-
Try to learn about a polymorphism ( Like a ScrewDriver can take may shapes according to your need then map to your objects if your using c# than try to leran about ToString() method overriding)
Step 6 -
Try to create a real life boundry to your real life object ( Like your House ; You secure your house by various means )
this is the initial learning .. read as much as text as you find and try to learn by your own examples
in the last ; oop is an art first , try to visulize it.
my main suggestion is to look at the objects as "smart serfs": each one of these will have memory (the data members) and logic (the member functions).
In my experience, the biggest strength of OOP is the control that you have on the evolution of your design: if your software is remotely useful, it will change, and OOP gives you tools to make the change sustainable. In particular:
a class should change for only one reason, so it must be solve only one problem (SINGLE RESPONSABILITY PRINCIPLE)
changing the behaviour of a class should be made by extending it, not by modifying it (OPEN CLOSED PRINCIPLE)
Focus on interfaces, not on inheritance
Tell, don't ask! Give orders to your objects, do not use them as "data stores"
There are other principles, but I think that these are the ones that must be really understood to succeed in OOP.
I'm not sure I ever understood OOP until I started programming in Ruby but I think I have a reasonable grasp of it now.
It was once explained to me as the components of a car and that helped a lot...
There's such a thing as a Car (the class).
my_car and girlfriends_car are both instances of Car.
my_car has these things that exist called Tyres.
my_car has four instances of Tyres - tyre1, tyre2, tyre3, tyre4
So I have two classes - Car, Tyre
and I have multiple instances of each class.
The Car class has an attribute called Car.colour.
my_car.colour is blue
girlfriends_car is pink
The sticking point for me was understanding the difference between class methods and instance methods.
Instance Methods
An instance method is something like my_car.paint_green. It wouldn't make any sense to call Car.paint_green. Paint what car green? Nope. It has to be girlfriend_car.wrap_around_tree because an instance method has to apply to an instance of that Class.
Class Methods
Say I wanted to build a car? my_new_car = Car.build
I call a Class method because it wouldn't make any sense to call it on an instance? my_car.build? my_car is already built.
Conclusion
If you're struggling to understand OOP then you should make sure that you understand the difference between the Class itself and instances of that Class. Furthermore, you should try to undesrstand the difference between class methods and instance methods. I'd recommend learning some Ruby or Python just so you can get a fuller understanding of OOP withouth the added complicaitons of writing OOP in a non-OOP language.
Great things happen with a true OOP language. In Ruby, EVERYTHING is a class. Even nothing (Nil) is a class. Strings are classes. Numbers are classes and every class is descended from the Object class so you can do neat things like inherit the instance_methods method from Object so String.instance_methods tells you all the instance methods for a string.
Hope that helps!
Kevin.
It seems like you're asking about the procedures or "how-tos" of OOP, not the concepts.
For the how-tos, you're mostly correct: I'm not specifically familiar with PHP or ActionScript, but for those of us in .NET, your program will have some entry point which will take control, and then it will call vairous objects, functions, methods, or whatever- often passing control to other pieces of code- to perform whatever you've decided.
In psuedo-code, it might look something like:
EntryPoint
Initialize (instanciate) a Person
Validate the Person's current properties
Perform some kind of update and/or calculation
provide result to user
Exit
If what you're looking for is the "why" then you're already looking in the right places. The very definitions of the terms Encapsulation, Inheritance, etc. will shed light on why we do OOP.
It's mostly about grouping code that belongs to certain areas together. In non-OOP languages you often have the problem that you can't tell which function is used for what/modifies which structures or functions tend to do too many loosely related things. One work around is to introduce a strict naming scheme (e.g. start every function name with the structure name it's associated with). With OOP, every function is tied to a data structure (the object) and thus makes it easier to organize your code. If you code gets larger/the number of tasks bigger inheritance starts to make a difference.
Good example is a structure representing a shape and a function that returns its center. In non-OOP, that function must distinguish between each structure. That's a problem if you add a new shape. You have to teach your function how to calculate the center for that shape. Now imagine you also had functions to return the circumfence and area and ... Inheritance solves that problem.
Note that you can do OOP programming in non-OOP languages (see for example glib/gtk+ in C) but a "real" OOP language makes it easier and often less error-prone to code in OOP-style. On the other hand, you can mis-use almost every OOP language to write purely imperative code :-) And no language prevents one from writing stupid and inefficient code, but that's another story.
Not sure what sort of answer you're looking for, but I think 10s of 1000s of newly graduated comp sci students will agree: no amount of books and theory is a substitute for practice. In other words, I can explain encapsulation, polymorphism, inheritance at length, but it won't help teach you how to use OO effectively.
No one can tell you how to program. Over time, you'll discover that, no matter how many different projects your working on, you're solving essentially the same problems over and over again. You'll probably ask yourself regularly:
How to represent an object or a process in a meaningful way to the client?
How do I reuse functionality without copy-pasting code?
What actually goes in a class / how fine-grained should classes be?
How do support variations in functionality in a class of objects based on specialization or type?
How do support variations in functionality without rewriting existing code?
How do I structure large applications to make them easy to maintain?
How do I make my code easy to test?
What I'm doing seems really convoluted / hacky, is there an easier way?
Will someone else be able to maintain the code when I'm finished?
Will I be able to maintain the code in 6 months or a year from now?
etc.
There are lots of books on the subject, and they can give you a good head start if you need a little advice. But trust me, time and practice are all you need, and it won't be too long -- maybe 6 or 9 months on a real project -- when OO idioms will be second nature.
What is a good gauge for knowing when a class is poorly designed or even necessary. In other words when to write a class and when no to.
SOLID might help if a class is poorly designed, but it won't help answer a question like "Is object-oriented programming the best approach for this problem?"
People have done a lot of very good work in programming for mathematics and science before object-oriented programming came into vogue. If your problem falls into those categories, perhaps object-oriented programming isn't for you.
Objects are state and behavior together; they tend to map onto problem domain objects one-to-one. If that's not true for your problem, perhaps object-oriented programming isn't for you.
If you don't know an object-oriented language well, perhaps object-oriented programming isn't for you.
If your organization doesn't know and can't support object-oriented solutions, perhaps object-oriented programming isn't for you.
A lot of people will say the "SOLID Principles" are a good guideline for class design.
There are a lot of articles/podcasts concerning the SOLID Principles, just do a quick search. Here's a good start:
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
rather than list a bunch of don't-do-this rules for recognizing a poorly-designed class, it is easier - and more efficient - to list the few rules governing a good class design:
a class is a collection of related state and behavior
the behavior should use only the state and method parameters
if you think about the state as a relation (i.e. as the columns in a relational database table), the object ID (pointer) is the primary (synthetic) key and the state comprises the non-key attributes. Is the object in third normal form? If not, split it into two or more objects.
is the lifecycle of the object complete? In other words, do you have enough methods to take the object from creation through use and finally to destruction/disposal? If not, what methods (or states/transitions) are missing?
is all of the state used by at least one method? If not, does it provide descriptive information useful to a user of the object? If the answer to both of these is no, then get rid of the extraneous state.
if the problem you're trying to solve requires no state, you don't need an object.
On top of the SOLID principles, have a look at Code Smells. They were mentioned first (IIRC) in Martin Fowler's "Refactoring" book, which is an excellent read.
Code smells generally apply to OO and also procedural development to some degree, including things like "Shotgun Surgery" where edits are required all over the codebase to change one small thing, or "Switch Case Smell" where giant switch cases control the flow of your app.
The best thing about Refactoring (book) is that it recommends ways to fix code smells and takes a pragmatic view about them - they are just like real smells - you can live with some of them, but not with others.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
My relative is studying programming and has a hard time understanding classes. He has trouble understanding for example that you need to instantiate it, that methods cannot access variables in other methods and if you change a variable in one instance of a class it doesn't change for other instances.
I've tried to use analogies like a class definition is like a blueprint of a house. And instances are houses made from that blueprint.
How do you explain classes and OO in general?
Seriously use Animals, it works great. And that's what nailed the concept for me years ago. Just found this C# code. It seems good
// Assembly: Common Classes
// Namespace: CommonClasses
public interface IAnimal
{
string Name
{
get;
}
string Talk();
}
// Assembly: Animals
// Namespace: Animals
public class AnimalBase
{
private string _name;
AnimalBase(string name)
{
_name = name;
}
public string Name
{
get
{
return _name;
}
}
}
// Assembly: Animals
// Namespace: Animals
public class Cat : AnimalBase, IAnimal
{
public Cat(String name) :
base(name)
{
}
public string Talk() {
return "Meowww!";
}
}
// Assembly: Animals
// Namespace: Animals
public class Dog : AnimalBase, IAnimal
{
public Dog(string name) :
base(name)
{
}
public string Talk() {
return "Arf! Arf!";
}
}
// Assembly: Program
// Namespace: Program
// References and Uses Assemblies: Common Classes, Animals
public class TestAnimals
{
// prints the following:
//
// Missy: Meowww!
// Mr. Bojangles: Meowww!
// Lassie: Arf! Arf!
//
public static void Main(String[] args)
{
List<IAnimal> animals = new List<IAnimal>();
animals.Add(new Cat("Missy"));
animals.Add(new Cat("Mr. Bojangles"));
animals.Add(new Dog("Lassie"));
foreach(IAnimal animal in animals)
{
Console.WriteLine(animal.Name + ": " + animal.Talk());
}
}
}
And once he's got this nailed, you challenge him to define Bird (fly), and then Penguin (fly!?)
The best way I got it through to my wife (a chartered accountant) is as follows.
In 'regular' programming you have data (things that are manipulated) and code (things that manipulate) and they're separate. Sometimes you get mixed up because a certain piece of code tries to manipulate the wrong thing.
In my wife's case, I said a invoice arrived (which involves no physical money changing hands) and accidentally updated a bank balance, something she immediately saw as potential fraud (she used to do forensic accounting, everything is potential fraud to her, including most of my share trades :-).
You could just as easily say that a piece of code meant to wash a floor with a huge mop decided to do it with your toothbrush.
With OO programming, the manipulators and manipulatees are inextricably entwined. You don't apply the floor washing process to the floor, instead you command the floor to wash itself. It knows how to do this because the code is part of the object, not something external to it.
In the accounting case above, I think we ended up having the chart of accounts as the object and we told it to apply a invoice to itself. Since it understood the process, it knew which accounts were allowed to be updated (creditors liability account and an expense account if I remember correctly).
Anyway, that's irrelevant and I'm just meandering now. What I'm saying is to express it in terms your target audience will understand. I suppose that's the secret of most teaching.
Like all old farts, I'd like to answer this with a story from my own life.
I started programming basic on a VIC-20. Not knowing anything else, I though this was how all computers were programmed. I thought it was a bit hard to keep track of which variable names I had used and which were still free, (scope problem). I also thought it was hard to divide my program into repeatable chunks using gosub-return and setting and reading the variables that these would use, (lack of methods).
Then I got into Turbo C over MS-DOS. Now I could create my own methods and functions! I was no longer stuck with the old finite set of commands in basic. I felt like I was creating a new language for every program I wrote. C gave me more expressive power.
C++ was the first object oriented language I heard about. The big moment for me was when I understood that I could create my own data types, and even overload the operators. Again, it felt like I could create my own language containing both new functions and data types, complete with operators.
That's how I would sell OO to a new programmer. Explain that it gives expressive power because they can define their own data types. I always thought encapsulation was a better selling point than inheritance.
I assume the target knows how to use graphical user interfaces. I found the best way is to describe OOP with stuff that they are really used for. Say
Class
A Window is a class. It has methods like
Show a window
Enable a window
Set the window's title
A Window has attributes. That is data associated with it. It is encapsulated into the class, together with the functions that operate on them
A Window has dimensions. Width and height.
A Window has possibly a parent window, and possibly children.
A Window has a title
Object
There are many windows. Each particular window is an object of the class Window. A Parent window containing 10 windows makes 11 Window objects.
Deriveration
A Button is a Window. It has dimensions has a parent window and has a title, the label of a button. It's a special kind of a window. When you ask for a window object, someone can give you a Button. A Button can add functions and data that are specific for a button:
A Button has a state. It can be in a pressed state, and unpressed state.
A Button can be the default button in a Window.
While you are explaining OO with animals, do not forget to illustrate the "is-a" relationship with Stinger missiles-armed kangaroos ;-)
The kangaroos scattered, as predicted, and the Americans nodded appreciatively . . . and then did a double-take as the kangaroos reappeared from behind a hill and launched a barrage of stinger missiles at the hapless helicopter. (Apparently the programmers had forgotten the remove "that" part of the infantry coding).
The lesson? Objects are defined with certain attributes, and any new object defined in terms of the old one inherits all the attributes. The embarrassed programmers had learned to be careful when reusing object-oriented code, and the Yanks left with the utmost respect for the Australian wildlife.
Read the Java tutorials for some good ideas and real world examples.
How about "each molding is built using a mold", or "each model is built using a template", and so "each object is built using a class" ?
Note that it works for class-oriented OOP (which is what you want), but not for prototype-oriented OOP.
As for explaining OOP to a programmer, I'd add examples illustrating:
Separating state from behavior
Most of the time, an instance describe a state, and a class describe a behavior.
Delegation
An instance delegates its behavior to its class, and the class in turn can delegate its behavior to its superclasses (or mixins or traits)
Polymorphism
If class A inherits from class B, an instance of A can be used anywhere an instance of class B can be used.
Messages & methods
A message (or generic function, or virtual function) is like a question. Most of the time, several classes can answer to this question.
A corresponding method is a possible answer to the question, that resides in a class.
When sending a message to an instance, the instance looks up for a corresponding method in its class. If found, it calls it (with the instance bound to 'self' or 'this'. Otherwise, it looks for a corresponding method in its mixins, traits, or superclasses, and calls it.
If they're old enough to have ever filled out a tax form, show them a 1040EZ and explain that an instance of a class is like a filled-out form: each blank is a member variable of the object, and the form also includes instructions for what to do with the member variables, and those instructions are the member functions of the object. A class itself is like a master copy of the form, from which you can print off an endless number of blank forms to fill out.
One thing that I would counsel to AVOID in trying to communicate the concepts of OO to new programmers is using only examples where objects (in the OO sense) represent real-world physical objects. This will actually make students more confused when they encounter objects used to represent non-physical objects (such as a color scheme, or most of the behavioral patterns in "Design Patterns") or objects used just as a useful way to store related functions and related data in the same place (think Java's java.lang.Math for an example.)
Believe it or not, sports!
I've had success in teaching and mentoring by talking about the way that e.g. a play for a football team is described in terms of how the various positions (Center, Quarterback, Runningback, etc.) interact to accomplish a particular goal. In one version, the positions correspond to classes, and specific persons (Tony Romo, Johnny Unitas, etc.) are instances of the class -- individuals who exhibit the same behaviors as defined by the positions.
The second version of this metaphor is to explain that the positions may be interfaces (in the Java sense) rather than classes. An interface really represents a role fulfilled by any object that implements the methods of the interface. And it's perfectly reasonable for an object (via its class, in Java) to implement multiple interfaces, just as it is possible for a talented individual to play more than one position on a sports team.
Finally, the play is like a pattern, in that it describes how a set of roles interact to accomplish some specific goal.
An object is a black box, which you can't see through. Public methods are buttons on them. Protected methods are buttons hidden on the bottom, private methods are dip switches inside.
Let's see a washer as an object. We don't know how it works. We don't care if it's powered by natural gas, diesel, electricity, or plutonium. However, the mechanism and internal structure will vary greatly depending on the energy source like a combustion engine is needed for some. We don't care as long as if we push a "Wash" button, it washes our clothes.
Let's turn the washer not Object-oriented. Expose all the buttons by arranging them on the top. Customers can now turbo-charge the engine by tweaking some dip switches. Make the chassis transparent. Now, you can see your energy-saving washing machine is actually hybrid-powered. There are some monkeys in it. You free them into the wild, and the machine eats up your utility bill like a gas-guzzler.
Object-oriented programming is one technique of raising the level of abstraction by means of which the programmer communicates with the computer: from the level of flipping individual bits on and off, from the level of punching holes in paper cards, from the level of extraordinarily complex sequences of basic instruction codes, from the level of less complicated definitions of reusable templates for blocks of data and reusable blocks of code (structs and procedures), to the level of transcribing the concepts in the programmer's mind into code, so that what goes on inside the computer comes to resemble, for the programmer, what goes on outside the computer in the world of physical objects, intangible assets, and cause-and-effect.
the best book i've ever on object-oriented programming is Betrand's "Object-Oriented Software Construction" - if you really want to get the basics, there is no way around it.
I explain that procedural program is built around the "verbs" of the system, the things you want the system to do, whereas object-oriented programming is build about the "nouns," the things in the system, and what they are capable of, and that for many people this allows for a more straightforward mapping from the problem domain to software.
For the example, I use cars -- "Honda Accord" is a class, whereas the vehicle sitting in the parking lot is an object, an instance of a Honda Accord. A Honda Accord is a sedan, which is a car, which is an automobile, which is a motorized vehicle, which is a mode of transportation, etc. I cannot do anything with a car until I have a physical car to work with -- it doesn't help me that the idea of a Honda Accord exists.
It also helps for discussing interfaces and polymorphism -- the gas pedal means accelerate, regardless what the car does behind the scenes to make that happen. There are "private" parts of the car that I as user do not have access to -- I cannot directly apply an individual brake.
Since the issue is to explain to a new programmer and not to a mother or a wife, I would go right straight to the point. OO is about three main concepts:
Inheritance: a dog is an animal, parent-child, is-a relationship test, etc.
Encapsulation: public-private (protected), information hiding, internal underlying details are not important to the users of the class, protect users from future changes in the implementation.
Polymorphism: run-time binding, late binding, method that gets invoked depends on the type of the object and not the reference or pointer to the object.
Also, depending on how much the new programmer has been doing a procedural language, I would need to help him/her unlearn that the functions or procedures are no longer central.
Games are good.
There are gameobjects, from this walls, enemies and players inherit.
The gameobjects should be renderable have collision-logic etc. The enemies have ai-logic while the player is keyboard controlled.
Some UI-elements are also good, there are buttons, inputboxes etc that all inherit from some baseobject that has code for managing mouse-events etc.
I don't like the animal-example because i've never seen a "real" program that has ever had to use of animals in that way. It will only make people use inheritance all over the place and you will end up with cubes inheriting from rectangles that inherit from lines (why does so many books insist on using this as example? ).
OOP is a higher level of abstraction, a programmer can't really come to grasp it unless he has a good understanding of the normal (read: procedural) way of programming, and he must be able to write some programs that do something useful.
For me it took a series of several lectures by one of my university profs, where he discussed many theoretical aspects of programming, he tried to convince us that programming is about manipulating data, and that this data is a representation of the "state(s)" of the program, and some other abstract stuff that I forgot now! But the point is, it's hard to understand OOP without some theoretical abstract discussion first, and this discussion wouldn't make any sense to a person who hadn't had experience writing some real code.
After the theoretical discussion, you give an example of a moderately complex program, written in procedural style, and slowly convert it, step by step, into object oriented style. After the concrete example, you should go back to the theoretical discussion and just summarize the main points, directly relate the theoretical constructs to the concrete example, e.g you can talk about how the name, age, and salary of an employee represent his state.
I must confess I'm somewhat of an OOP skeptic. Bad pedagogical and laboral experiences with object orientation didn't help. So I converted into a fervent believer in Visual Basic (the classic one!).
Then one day I found out C++ had changed and now had the STL and templates. I really liked that! Made the language useful. Then another day MS decided to apply facial surgery to VB, and I really hated the end result for the gratuitous changes (using "end while" instead of "wend" will make me into a better developer? Why not drop "next" for "end for", too? Why force the getter alongside the setter? Etc.) plus so much Java features which I found useless (inheritance, for instance, and the concept of a hierarchical framework).
And now, several years afterwards, I find myself asking this philosophical question: Is inheritance really needed?
The gang-of-four say we should favor object composition over inheritance. And after thinking of it, I cannot find something you can do with inheritance you cannot do with object aggregation plus interfaces. So I'm wondering, why do we even have it in the first place?
Any ideas? I'd love to see an example of where inheritance would be definitely needed, or where using inheritance instead of composition+interfaces can lead to a simpler and easier to modify design. In former jobs I've found if you need to change the base class, you need to modify also almost all the derived classes for they depended on the behaviour of parent. And if you make the base class' methods virtual... then not much code sharing takes place :(
Else, when I finally create my own programming language (a long unfulfilled desire I've found most developers share), I'd see no point in adding inheritance to it...
Really really short answer: No. Inheritance is not needed because only byte code is truly needed. But obviously, byte code or assemble is not a practically way to write your program. OOP is not the only paradigm for programming. But, I digress.
I went to college for computer science in the early 2000s when inheritance (is a), compositions (has a), and interfaces (does a) were taught on an equal footing. Because of this, I use very little inheritance because it is often suited better by composition. This was stressed because many of the professors had seen bad code (along with what you have described) because of abuse of inheritance.
Regardless of creating a language with or without inheritances, can you create a programming language which prevents bad habits and bad design decisions?
I think asking for situations where inheritance is really needed is missing the point a bit. You can fake inheritance by using an interface and some composition. This doesnt mean inheritance is useless. You can do anything you did in VB6 in assembly code with some extra typing, that doesn't mean VB6 was useless.
I usually just start using an interface. Sometimes I notice I actually want to inherit behaviour. That usually means I need a base class. It's that simple.
Inheritance defines an "Is-A" relationship.
class Point( object ):
# some set of features: attributes, methods, etc.
class PointWithMass( Point ):
# An additional feature: mass.
Above, I've used inheritance to formally declare that PointWithMass is a Point.
There are several ways to handle object P1 being a PointWithMass as well as Point. Here are two.
Have a reference from PointWithMass object p1 to some Point object p1-friend. The p1-friend has the Point attributes. When p1 needs to engage in Point-like behavior, it needs to delegate the work to its friend.
Rely on language inheritance to assure that all features of Point are also applicable to my PointWithMass object, p1. When p1 needs to engage in Point-like behavior, it already is a Point object and can just do what needs to be done.
I'd rather not manage the extra objects floating around to assure that all superclass features are part of a subclass object. I'd rather have inheritance to be sure that each subclass is an instance of it's own class, plus is an instance of all superclasses, too.
Edit.
For statically-typed languages, there's a bonus. When I rely on the language to handle this, a PointWithMass can be used anywhere a Point was expected.
For really obscure abuse of inheritance, read about C++'s strange "composition through private inheritance" quagmire. See Any sensible examples of creating inheritance without creating subtyping relations? for some further discussion on this. It conflates inheritance and composition; it doesn't seem to add clarity or precision to the resulting code; it only applies to C++.
The GoF (and many others) recommend that you only favor composition over inheritance. If you have a class with a very large API, and you only want to add a very small number of methods to it, leaving the base implementation alone, I would find it inappropriate to use composition. You'd have to re-implement all of the public methods of the encapsulated class to just return their value. This is a waste of time (programmer and CPU) when you can just inherit all of this behavior, and spend your time concentrating on new methods.
So, to answer your question, no you don't absolutely need inheritance. There are, however, many situations where it's the right design choice.
The problem with inheritance is that it conflates the issue of sub-typing (asserting an is-a relationship) and code reuse (e.g., private inheritance is for reuse only).
So, no it's an overloaded word that we don't need. I'd prefer sub-typing (using the 'implements' keyword) and import (kinda like Ruby does it in class definitions)
Inheritance lets me push off a whole bunch of bookkeeping onto the compiler because it gives me polymorphic behavior for object hierarchies that I would otherwise have to create and maintain myself. Regardless of how good a silver bullet OOP is, there will always be instances where you want to employ a certain type of behavior because it just makes sense to do. And ultimately, that's the point of OOP: it makes a certain class of problems much easier to solve.
The downsides of composition is that it may disguise the relatedness of elements and it may be harder for others to understand. With,say, a 2D Point class and the desire to extend it to higher dimensions, you would presumably have to add (at least) Z getter/setter, modify getDistance(), and maybe add a getVolume() method. So you have the Objects 101 elements: related state and behavior.
A developer with a compositional mindset would presumably have defined a getDistance(x, y) -> double method and would now define a getDistance(x, y, z) -> double method. Or, thinking generally, they might define a getDistance(lambdaGeneratingACoordinateForEveryAxis()) -> double method. Then they would probably write createTwoDimensionalPoint() and createThreeDimensionalPoint() factory methods (or perhaps createNDimensionalPoint(n) ) that would stitch together the various state and behavior.
A developer with an OO mindset would use inheritance. Same amount of complexity in the implementation of domain characteristics, less complexity in terms of initializing the object (constructor takes care of it vs. a Factory method), but not as flexible in terms of what can be initialized.
Now think about it from a comprehensibility / readability standpoint. To understand the composition, one has a large number of functions that are composed programmatically inside another function. So there's little in terms of static code 'structure' (files and keywords and so forth) that makes the relatedness of Z and distance() jump out. In the OO world, you have a great big flashing red light telling you the hierarchy. Additionally, you have an essentially universal vocabulary to discuss structure, widely known graphical notations, a natural hierarchy (at least for single inheritance), etc.
Now, on the other hand, a well-named and constructed Factory method will often make explicit more of the sometimes-obscure relationships between state and behavior, since a compositional mindset facilitates functional code (that is, code that passes state via parameters, not via this ).
In a professional environment with experienced developers, the flexibility of composition generally trumps its more abstract nature. However, one should never discount the importance of comprehensibility, especially in teams that have varying degrees of experience and/or high levels of turnover.
Inheritance is an implementation decision. Interfaces almost always represent a better design, and should usually be used in an external API.
Why write a lot of boilerplate code forwarding method calls to a composed member object when the compiler will do it for you with inheritance?
This answer to another question summarises my thinking pretty well.
Does anyone else remember all of the OO-purists going ballistic over the COM implementation of "containment" instead of "inheritance?" It achieved essentially the same thing, but with a different kind of implementation. This reminds me of your question.
I strictly try to avoid religious wars in software development. ("vi" OR "emacs" ... when everybody knows its "vi"!) I think they are a sign of small minds. Comp Sci Professors can afford to sit around and debate these things. I'm working in the real world and could care less. All of this stuff are simply attempts at giving useful solutions to real problems. If they work, people will use them. The fact that OO languages and tools have been commercially available on a wide scale for going on 20 years is a pretty good bet that they are useful to a lot of people.
There are a lot of features in a programming language that are not really needed. But they are there for a variety of reasons that all basically boil down to reusability and maintainability.
All a business cares about is producing (quality of course) cheaply and quickly.
As a developer you help do this is by becoming more efficient and productive. So you need to make sure the code you write is easily reusable and maintainable.
And, among other things, this is what inheritance gives you - the ability to reuse without reinventing the wheel, as well as the ability to easily maintain your base object without having to perform maintenance on all similar objects.
There's lots of useful usages of inheritance, and probably just as many which are less useful. One of the useful ones is the stream class.
You have a method that should be able stream data. By using the stream base class as input to the method you ensure that your method can be used to write to many kinds of streams without change. To the file system, over the network, with compression, etc.
No.
for me, OOP is mostly about encapsulation of state and behavior and polymorphism.
and that is. but if you want static type checking, you'll need some way to group different types, so the compiler can check while still allowing you to use new types in place of another, related type. creating a hierarchy of types lets you use the same concept (classes) for types and for groups of types, so it's the most widely used form.
but there are other ways, i think the most general would be duck typing, and closely related, prototype-based OOP (which isn't inheritance in fact, but it's usually called prototype-based inheritance).
Depends on your definition of "needed". No, there is nothing that is impossible to do without inheritance, although the alternative may require more verbose code, or a major rewrite of your application.
But there are definitely cases where inheritance is useful. As you say, composition plus interfaces together cover almost all cases, but what if I want to supply a default behavior? An interface can't do that. A base class can. Sometimes, what you want to do is really just override individual methods. Not reimplement the class from scratch (as with an interface), but just change one aspect of it. or you may not want all members of the class to be overridable. Perhaps you have only one or two member methods you want the user to override, and the rest, which calls these (and performs validation and other important tasks before and after the user-overridden methods) are specified once and for all in the base class, and can not be overridden.
Inheritance is often used as a crutch by people who are too obsessed with Java's narrow definition of (and obsession with) OOP though, and in most cases I agree, it's the wrong solution, as if the deeper your class hierarchy, the better your software.
Inheritance is a good thing when the subclass really is the same kind of object as the superclass. E.g. if you're implementing the Active Record pattern, you're attempting to map a class to a table in the database, and instances of the class to a row in the database. Consequently, it is highly likely that your Active Record classes will share a common interface and implementation of methods like: what is the primary key, whether the current instance is persisted, saving the current instance, validating the current instance, executing callbacks upon validation and/or saving, deleting the current instance, running a SQL query, returning the name of the table that the class maps to, etc.
It also seems from how you phrase your question that you're assuming that inheritance is single but not multiple. If we need multiple inheritance, then we have to use interfaces plus composition to pull off the job. To put a fine point about it, Java assumes that implementation inheritance is singular and interface inheritance can be multiple. One need not go this route. E.g. C++ and Ruby permit multiple inheritance for your implementation and your interface. That said, one should use multiple inheritance with caution (i.e. keep your abstract classes virtual and/or stateless).
That said, as you note, there are too many real-life class hierarchies where the subclasses inherit from the superclass out of convenience rather than bearing a true is-a relationship. So it's unsurprising that a change in the superclass will have side-effects on the subclasses.
Not needed, but usefull.
Each language has got its own methods to write less code. OOP sometimes gets convoluted, but I think that is the responsability of the developers, the OOP platform is usefull and sharp when it is well used.
I agree with everyone else about the necessary/useful distinction.
The reason I like OOP is because it lets me write code that's cleaner and more logically organized. One of the biggest benefits comes from the ability to "factor-up" logic that's common to a number of classes. I could give you concrete examples where OOP has seriously reduced the complexity of my code, but that would be boring for you.
Suffice it to say, I heart OOP.
Absolutely needed? no,
But think of lamps. You can create a new lamp from scratch each time you make one, or you can take properties from the original lamp and make all sorts of new styles of lamp that have the same properties as the original, each with their own style.
Or you can make a new lamp from scratch or tell people to look at it a certain way to see the light, or , or, or
Not required, but nice :)
Thanks to all for your answers. I maintain my position that, strictly speaking, inheritance isn't needed, though I believe I found a new appreciation for this feature.
Something else: In my job experience, I have found inheritance leads to simpler, clearer designs when it's brought in late in the project, after it's noticed a lot of the classes have much commonality and you create a base class. In projects where a grand-schema was created from the very beginning, with a lot of classes in an inheritance hierarchy, refactoring is usually painful and dificult.
Seeing some answers mentioning something similar makes me wonder if this might not be exactly how inheritance's supposed to be used: ex post facto. Reminds me of Stepanov's quote: "you don't start with axioms, you end up with axioms after you have a bunch of related proofs". He's a mathematician, so he ought to know something.
The biggest problem with interfaces is that they cannot be changed. Make an interface public, then change it (add a new method to it) and break million applications all around the world, because they have implemented your interface, but not the new method. The app may not even start, a VM may refuse to load it.
Use a base class (not abstract) other programmers can inherit from (and override methods as needed); then add a method to it. Every app using your class will still work, this method just won't be overridden by anyone, but since you provide a base implementation, this one will be used and it may work just fine for all subclasses of your class... it may also cause strange behavior because sometimes overriding it would have been necessary, okay, might be the case, but at least all those million apps in the world will still start up!
I rather have my Java application still running after updating the JDK from 1.6 to 1.7 with some minor bugs (that can be fixed over time) than not having it running it at all (forcing an immediate fix or it will be useless to people).
//I found this QA very useful. Many have answered this right. But i wanted to add...
1: Ability to define abstract interface - E.g., for plugin developers. Of course, you can use function pointers, but this is better and simpler.
2: Inheritance helps model types very close to their actual relationships. Sometimes a lot of errors get caught at compile time, because you have the right type hierarchy. For instance, shape <-- triangle (lets say there is a lot of code to be reused). You might want to compose triangle with a shape object, but shape is an incomplete type. Inserting dummy implementations like double getArea() {return -1;} will do, but you are opening up room for error. That return -1 can get executed some day!
3: void func(B* b); ... func(new D()); Implicit type conversion gives a great notational convenience since Derived is Base. I remember having read Straustrup saying that he wanted to make classes first class citizens just like fundamental data types (hence overloading operators etc). Implicit conversion from Derived to Base, behaves just like an implicit conversion from a data type to broader compatible one (short to int).
Inheritance and Composition have their own pros and cons.
Refer to this related SE question on pros of inheritance and cons of composition.
Prefer composition over inheritance?
Have a look at the example in this documentation link:
The example shows different use cases of overriding by using inheritance as a mean to achieve polymorphism.
In the following, inheritance is used to present a particular property for all of several specific incarnations of the same type thing. In this case, the GeneralPresenation has a properties that are relevant to all "presentation" (the data passed to an MVC view). The Master Page is the only thing using it and expects a GeneralPresentation, though the specific views expect more info, tailored to their needs.
public abstract class GeneralPresentation
{
public GeneralPresentation()
{
MenuPages = new List<Page>();
}
public IEnumerable<Page> MenuPages { get; set; }
public string Title { get; set; }
}
public class IndexPresentation : GeneralPresentation
{
public IndexPresentation() { IndexPage = new Page(); }
public Page IndexPage { get; set; }
}
public class InsertPresentation : GeneralPresentation
{
public InsertPresentation() {
InsertPage = new Page();
ValidationInfo = new PageValidationInfo();
}
public PageValidationInfo ValidationInfo { get; set; }
public Page InsertPage { get; set; }
}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
Improve this question
When designing a new system or getting your head around someone else's code, what are some tell tale signs that something has gone wrong in the design phase? Are there clues to look for on class diagrams and inheritance hierarchies or even in the code itself that just scream for a design overhaul, particularly early in a project?
The things that mostly stick out for me are "code smells".
Mostly I'm sensitive to things that go against "good practice".
Things like:
Methods that do things other than what you'd think from the name (eg: FileExists() that silently deletes zero byte files)
A few extremely long methods (sign of an object wrapper around a procedure)
Repeated use of switch/case statements on the same enumerated member (sign of sub-classes needing extraction)
Lots of member variables that are used for processing, not to capture state (might indicate need to extract a method object)
A class that has lots of responsibilities (violation of Single Repsonsibility principle)
Long chains of member access (this.that is fine, this.that.theOther is fine, but my.very.long.chain.of.member.accesses.for.a.result is brittle)
Poor naming of classes
Use of too many design patterns in a small space
Working too hard (rewriting functions already present in the framework, or elsewhere in the same project)
Poor spelling (anywhere) and grammar (in comments), or comments that are simply misleading
I'd say the number one rule of poor OO design (and yes I've been guilty of it too many times!) is:
Classes that break the Single
Responsibility Principle (SRP) and
perform too many actions
Followed by:
Too much inheritance instead of
composition, i.e. Classes that
derive from a sub-type purely so
they get functionality for free.
Favour Composition over Inheritance.
Impossible to unit test properly.
Anti-patterns
Software design anti-patterns
Abstraction inversion : Not exposing implemented functionality required by users, so that they re-implement it using higher level functions
Ambiguous viewpoint: Presenting a model (usually OOAD) without specifying its viewpoint
Big ball of mud: A system with no recognizable structure
Blob: Generalization of God object from object-oriented design
Gas factory: An unnecessarily complex design
Input kludge: Failing to specify and implement handling of possibly invalid input
Interface bloat: Making an interface so powerful that it is extremely difficult to implement
Magic pushbutton: Coding implementation logic directly within interface code, without using abstraction.
Race hazard: Failing to see the consequence of different orders of events
Railroaded solution: A proposed solution that while poor, is the only one available due to poor foresight and inflexibility in other areas of the design
Re-coupling: Introducing unnecessary object dependency
Stovepipe system: A barely maintainable assemblage of ill-related components
Staralised schema: A database schema containing dual purpose tables for normalised and datamart use
Object-oriented design anti-patterns
Anemic Domain Model: The use of domain model without any business logic which is not OOP because each object should have both attributes and behaviors
BaseBean: Inheriting functionality from a utility class rather than delegating to it
Call super: Requiring subclasses to call a superclass's overridden method
Circle-ellipse problem: Subtyping variable-types on the basis of value-subtypes
Empty subclass failure: Creating a class that fails the "Empty Subclass Test" by behaving differently from a class derived from it without modifications
God object: Concentrating too many functions in a single part of the design (class)
Object cesspool: Reusing objects whose state does not conform to the (possibly implicit) contract for re-use
Object orgy: Failing to properly encapsulate objects permitting unrestricted access to their internals
Poltergeists: Objects whose sole purpose is to pass information to another object
Sequential coupling: A class that requires its methods to be called in a particular order
Singletonitis: The overuse of the singleton pattern
Yet Another Useless Layer: Adding unnecessary layers to a program, library or framework. This became popular after the first book on programming patterns.
Yo-yo problem: A structure (e.g., of inheritance) that is hard to understand due to excessive fragmentation
This question makes the assumption that object-oriented means good design. There are cases where another approach is much more appropriate.
One smell is objects having hard dependencies/references to other objects that aren't a part of their natural object hierarchy or domain related composition.
Example: Say you have a city simulation. If the a Person object has a NearestPostOffice property you are probably in trouble.
One thing I hate to see is a base class down-casting itself to a derived class. When you see this, you know you have problems.
Other examples might be:
Excessive use of switch statements
Derived classes that override everything
In my view, all OOP code degenerates to procedural code over a sufficiently long time span.
Granted, if you read my most recent question, you might understand why I am a little jaded.
The key problem with OOP is that it doesn't make it obvious that your object construction graph should be independent of your call graph.
Once you fix that problem, OOP actually starts to make sense. The problem is that very few teams are aware of this design pattern.
Here's a few:
Circular dependencies
You with property XYZ of a base class wasn't protected/private
You wish your language supported multiple inheritance
Within a long method, sections surrounded with #region / #endregion - in almost every case I've seen, that code could easily be extracted into a new method OR needed to be refactored in some way.
Overly-complicated inheritance trees, where the sub-classes do very different things and are only tangentially related to one another.
Violation of DRY - sub-classes that each override a base method in almost exactly the same way, with only a minor variation. An example: I recently worked on some code where the subclasses each overrode a base method and where the only difference was a type test ("x is ThisType" vs "x is ThatType"). I implemented a method in the base that took a generic type T, that it then used in the test. Each child could then call the base implementation, passing the type it wanted to test against. This trimmed about 30 lines of code from each of 8 different child classes.
Duplicate code = Code that does the same thing...I think in my experience this is the biggest mistake that can occur in OO design.
Objects are good create a gazillion of them is a bad OO design.
Having all you objects inherit some base utility class just so you can call your utility methods without having to type so much code.
Find a programmer who is experienced with the code base. Ask them to explain how something works.
If they say "this function calls that function", their code is procedural.
If they say "this class interacts with that class", their code is OO.
Following are most prominent features of a bad design:
Rigidity
Fragility
Immobility
Take a look at The Dependency Inversion Principle
When you don't just have a Money\Amount class but a TrainerPrice class, TablePrice class, AddTablePriceAction class and so on.
IDE Driven Development or Auto-Complete development. Combined with extreme strict typing is a perfect storm.
This is where you see what could be a lot of what could be variable values become class names and method names as well as the gratuitous use of classes in general. You'll also see things like all primitives becoming objects. All literals as classes. Function parameters as classes. Then conversion methods everywhere. You'll also see things like a class wrapping another delivering a subset of methods to another class inclusive of only the ones it needs at present.
This creates the possibility to generate an near infinite amount of code which is great if you have billable hours. When variables, contexts, properties and states get unrolled into hyper explicit and overly specific classes then this creates an exponential cataclysm as sooner or later those things multiply. Think of it like [a, b] x [x, y]. This can be further compounded by an attempt to create a full fluent interface as well as adhere to as many design patterns as possible.
OOP languages are not as polymorphic as some loosely typed languages. Loosely typed languages often offer runtime polymorphism in shallow syntax that static analysis can't handle.
In OOP you might see forms of repetition hard to automatically detect that could be turned into more dynamic code using maps. Although such languages are less dynamic you can achieve dynamic features with some extra-work.
The trade of here is that you save thousands (or millions) of lines of code while potentially loosing IDE features and static analysis. Performance can go either way. Run time polymorphism can often be converted to generated code. However in some cases the space is so huge that anything other than runtime polymorphism is impossible.
Problems are a lot more common with OOP languages lacking generics and when OOP programmers try to strictly type dynamic loosely typed language.
What happens without generics is where you should have A for X = [Q, W, E] and Y = [R, T, Y] you instead see [AQR, AQT, AQY, AWR, AWT, AWY, AER, AET, AEY]. This is often due to fear or using typeless or passing the type as a variable for loosing IDE support.
Traditionally loosely typed languages are made with a text editor rather than an IDE and the advantage lost through IDE support is often gained in other ways such as organising and structuring code such that it is navigable.
Often IDEs can be configured to understand your dynamic code (and link into it) but few properly support it in a convenient manner.
Hint: The context here is OOP gone horrifically wrong in PHP where people using simple OOP Java programming traditionally have tried to apply that to PHP which even with some OOP support is a fundamentally different type of language.
Designing against your platform to try to turn it into one your used to, designing to cater to an IDE or other tools, designing to cater to supporting Unit Tests, etc should all ring alarm bells because it's a significant deviation away from designing working software to solve a given category of problems or a given feature set.