One of the complain about OO is that it does not reflect the real world because not everything in the eral world is object. However, I think people play with word on this one rather focus on the idea. Let's not call it object, but call it concept. An object in OOP reflects a real world concepts, not an object as in noun. For instance, kicking is an action which can be modeled by a class named Kick along with its attributes to present it as a concept:
class Kick{
private:
int velocity_;
int force_;
public:
Kick(int velocity, int force):velocity_(velocity),force_(force){}
virtual ~Kick(){}
void high(Fighter target){ /*implement high kick */ }
void mid(Fighter target){ /*implement mid kick */ }
void low(Fighter target){ /* implement low kick */ }
int get_velocity() const { return velocity_; }
int get_force() const { return force_; }
};
class Fighter{
private:
int health_;
int ki_;
Kick kicking_stance_;
public:
enum AttackPosition {
high,
mid,
low,
};
FIghter(int health, int ki, int kick_stance):health_(health), ki_(ki), kicking_stance_(kick_stance){}
virtual ~Fighter(){}
void kick(Fighter target, AttackPosition pos){
if (pos == high) kicking_stance_.high(target);
else if (pos == mid) kicking_stance_.mid(target);
else kicking_stance_.low(target);
}
};
So, what's the problem here? I think one of the reason people complain that is, Kick is not an object in real world itself. Only live entity like human, horses can kick. Another example is, if I got an Invoice class, should object of invocie, invokes actions like invoice.save(), invoice.send()? For this reason, we have patterns, design and design principles because pretty much people can invent different ways to present a concept. As a consequence, OO is accused for low reusability, despite the abstraction is for concept reusability. In the example above, other people might put Kick concept inside an abstract class Fighter, while other might define the MartialArtStyle abstract class, and put kick action inside it as a abstract method. For this reason, it's more difficult to reuse, since if there's a more complicated object system, a member function of an object may operate on the abstract data type of that object, and inside the abstract data type, it operates on other abstract data types as well.
This is what I got from the articles. Correct me if I'm wrong.
However, I still don't think it's the fault of the paradigm, but rather, the language. Let's consider another scenario:
- An ancient wizard has a powerful spell which can turn objects (such as tea cup) into living entity like human being.
- There's a tea cup in front of him
- The old wizard casts the spell on the tea cup to make it live.
In language like Java, the problem is that I have to plan ahead for TeaCup object. If I want to have a tea cup to behave like human, I have to:
- Write an interface for shared human behaviors, such as talk(), walk(), and let TeaCup implement it.
- Since not all TeaCup can talk, and I want to model the real work closely so other can understand, the TeaCup must not always talk.
- So, I define a TeaCup hierarchy, which (for simplicity, I will create one) has TalkingTeaCup inherits from TeaCup (which is the normal one), and implements the shared human behaviors interface.
Look at this way of constructing concept, we can see that it creates overhead. In this case, instead of a tea cup with has varied behaviors, we got different versions of TeaCup which varies a little in behaviors. This is just another simple case. Imagine if it applies for a large and complicated system.
There's no way for me to keep the TeaCup object as simple as it is, because TeaCup is a TeaCup, it can't operate on it own until the wizard gives it a life. Thus, TeaCup must not contain any related behaviors to make it "lively" (to prevent issue like whether invoice should save() / send() or not). Dynamic behaviors will be added later after the wizard casts life spell on TeaCup.
I don't think we can add methods to TeaCup if we don't write it in class or implement via interface. Although, Java can dynamically add more class with varied parameter at runtime with Dynamic Object Mode (which we have to do more work)l: http://dirkriehle.co...005/plopd-5.pdf . In C, we can have an array of function pointers, however, this approach is not convenient, since it operates on low level, so it's error-prone and it is strong typing, which make it less flexible.
With function as first class object, it creates a more elegant way to solve the above problem. Consider this piece of Lisp code (I'm learning, so pardon me if it's not elegant) written for this scenario:
//I have to use C comment because our forum does not support Lisp comment style.
//collection of wizard spells. In Lisp, a variable is just a list, which might be a single value, or a list of symbols/values/functions
(defparameter *wizard-spells* nil)
//class object with its attributes consists of name and action
(defstruct object name action)
/* This is the wizard spell for giving an object a life. Here you can see, upon calling this function, it will add function talk and walk into the variable action of the class object */
(defmethod giving-life ((o object))
(princ ( type-of o))
(princ " is now as lively as human!")
(push #'talk (object-action o))
(push #'walk (object-action o)))
//wizard spell for making an object become poisonous, so if someone contacts with the object, they will die a moment later
(defmethod poison ((o object))
(princ ( type-of o))
(princ " is covered with poison."))
//talk action, which is a human behavior
(defun talk ()
(princ "Hello I can talk now"))
//walk action, which is a human behavior
(defun walk ()
(princ "Hello I can walk now"))
//add spells to spell collection of the wizard
(push #'giving-life *wizard-spells*)
(push #'poison *wizard-spells*)
//create a teacup
(defparameter *tea-cup* (make-object :name "TeaCup" :action nil))
//funcall will execute the functions inside the variables.
(funcall (nth 1 *wizard-spells*) *tea-cup*)
(funcall (nth 0 (object-action *tea-cup*)))
(funcall (nth 1 (object-action *tea-cup*)))
In sum, OOP creates or more flexible way for "creativity" (in which we call design, where people can create different abstractions for the same concepts. This might be a good or bad thing). Those are the ideas I "suddenly" got it after practicing with Lisp for a while. Not sure if it's to the point or not, so If you guys can verify it, I am really thankful.