Should my API use nonmember functions to act on an object, or make the functions public functions of the object?
Recently I have learnt of the many benefits (including beautiful looking code) of OOP.
So, now I am trying to write a small physics API for my personal use, perhaps to be put in a few little games. This is mainly because I like to practice coding, and I like my physics.
But the thing is, many APIs have an interface like this (including the Windows API):
// In this case, Object is just a plain data container without a constructor.
Object object = NewObject(...);
DoSomething(object);
DoAnotherThing(object,...);
... and so on
Is this how APIs should be arranged, or is there are more OO-style way of things, like:
Object object(...);
object.DoSomething(...);
object.DoAnother(otherObj,...);
otherObject.attachNode(object);
... and so on again
I hope you get the idea. So, to summarise by question, which method is more prefered, and why is it that I see a lot of the first example despite the glorification of OOP (though perhaps these APIs开发者_JAVA技巧 in reference are just old, like the Windows API).
As a side note, what do you think of the Windows API? To me it seems just a bit... not right.
An API can look any way you want it to. If you want to make a C++ API, then you can use member functions as much as you like. With the Win32 API, Microsoft had to make something that was accessible from C (and a variety of other languages) as well as C++, so they had to express everything using features that are universally accessible. That means they couldn't use classes (or by extension, member functions), namespaces, overloading, templates and a variety of other C++ features.
They then took that pretty reasonable premise, and built the ugliest, most inconsistent API imaginable.
If your API is intended to be used from C++ code, then you can use all the C++ features you like.
On a side note, even in C++, making everything a member function isn't necessarily preferable. Using non-member functions by default can be a very good idea, even in object-oriented code, although the reasons are different than the ones Microsoft had for it in their API.
One of the pillars of object oriented programming is encapsulation. As little code as possible should be dependent on the internals of an object, because those internals could potentially change. Member functions can access those internals, non-member (non-friend) functions cannot.
This means that do_something(object)
is actually more OO than object.do_something()
, and a lot of OO officionados don't seem to get that at all.
Of course this is an oversimplification. If you need dynamic dispatch, you have to use member functions. See Item 23 in Effective C++ or click on How Non-Member Functions Improve Encapsulation for details.
I think this is a highly subjective topic.
While I tend to prefer the object.DoSomething()
style, I see nothing wrong with the other way. I would even say that sometimes, it makes more sense.
I believe what really matters is that your API remains consistent.
Usually, when the selected style is not adequate, you notice it because some things seem wrong.
It depends on whether you expect the API to work with OO and non-OO code. Your example, the Windows API, was designed to work with non-OO code primarily (at least, initially). So if you are sure that your users are using only OO languages (especially if it's just for your own projects), just stick with whatever is natural for the language you're working with. So for C++, I'd go with the second option and use the language's features to their fullest potential.
This document might not be a 100% fit to the question but nevertheless closely related. Scott Meyers discusses both styles mentioned in the question. Scott Meyers: How Non-Member Functions Improve Encapsulation
The former system is C-like. The latter is the OO way of doing things.
If you're not bound with some performance constraints, use object methods. In this case, choice of methods is limited, and in C-style you have all possible methods to choose from. Human memory is limited, so divide everything in small (and testable!) parts.
You should not confuse spelling with design.
object.Foo()
is just a way of spelling that says you're calling the Foo method on object. Another OO language could use the spelling CallMethod(object, Foo)
to mean exactly the same. Or it could use the Foo(object)
syntax.
Now the Windows API is an API that's intended to be used by OO and non-OO languages alike. You appear to be using the C binding of the Windows API, the binding that you get from #include <windows.h>
. C is not OO at all. Therefore windows.h
doesn't seem like an OO API from a C++ perspective.
精彩评论