Page 3 of 10

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 8:44 am
by josh
Jonah Bron wrote:So you're saying it's good because it allows an object to "inherit" multiple objects?
No, it allows you to use them. No inheritance is taking place, however the larger point is that "use" of an object provides all the same benefits of inheriting it.

And yes Vlad is right inheritance tackles a larger problem. But when you dependency inject (use composition) that problem vanishes, and inheritance is not needed as much. Once you start using interfaces its technically not needed at all.

Take your classic Cat vs Dog example. Both historically extending Animal. Well in a more modern program, both would implement Animal, not extend it. Instead of there being a walk() method on the Animal class, there would be no animal class. Instead, both Dog & Cat have a walk() method that delegates to a "walking strategy" (the strategy each animal should use would be configured thru a setting, passed to the constructor or set from some database or config file).

We no longer need an animal class, just an animal interface. Now we can use that walk() method on non-animals, namely killer robots where we don't need a breathe(), eat(), drink(), or sleep() unwanted methods that would come from having robot extend animal. WIth inheritance you only wanted the walk() method but you took a bunch of extra methods you didn't want too. With composition you can take what is needed. Also there's animals that don't walk. Inheritance fails at modeling the real world I live in.

Sure you could put the walk() method in a class WalkingAnimal that extends Animal, and have your Cat class extend that. But you're already making an explosion of classes for no reason, and I haven't even given you a difficult requirement ;-)... also it doesn't solve the killer-robot requirement.

With interfaces & composition, there is no more diamond problem. Your dog implements "breathing", & "walking". Your killer-robot implements "killing", & "walking". You use composition (strategy pattern in this case) so that both dogs & robots can walk, without having to copy paste (except for 1 line method that delegates to the walking strategy)*. Not only does this solve the diamond problem but it will promote better practice. You can break up your logic for walking within it's own walking class now. It follows the single responsibility principle in a simple or complex program, whereas inheritance you eventually end up breaking the single responsibility principle, or duplicating code, or having excess methods that aren't needed in a particular sub-class)

* only prototypical inheritance "solves" this as far as I know, but I don't see it as a thing to solve. I see it as a place to put security checks, etc.

With all this being said, inheritance may be more elegant in certain situations. But if you code from a business perspective, factor in unknown user requests, etc.. composition provides more benefit & less business risk. Objects in real life don't exist in a hierarchy, its a flawed way of looking at the world and there will eventually be a wrench in your gears some day for some user request.

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 11:02 am
by VladSun
josh wrote:Objects in real life don't exist in a hierarchy
What about you and your parents :)
You are a "composite object" (i.e. body "object", hand "object", etc.), but by definition you inherit your body (and mind) model from your parents - the DNA.
That's what I had in mind when I mentioned "skeleton (maybe template)" pattern vs strategy pattern"...

What about the Darwin's theory? :P

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 11:14 am
by Jenk
Given the advances made in surgery, and the ability to operate transplants quite successfully, I'd argue the body is a composite of organs. :P

In my blunt opinion, Composition is simply more OO than inheritance. You are violating the black-box rule by inheriting and overriding the internals of the parent object.

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 11:19 am
by John Cartwright
Jenk wrote:Given the advances made in surgery, and the ability to operate transplants quite successfully, I'd argue the body is a composite of organs. :P

In my blunt opinion, Composition is simply more OO than inheritance. You are violating the black-box rule by inheriting and overriding the internals of the parent object.
I agree. Most inheritance can be more cleanly written with interfaces and composition.

However, there will always be edge cases where inheritance, and even multiple inheritance, makes more sense. Well.. maybe not in PHP :D

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 11:21 am
by John Cartwright
VladSun wrote:What about the Darwin's theory? :P
Oh my. A discussion about about abstraction -> turns into a discussion about composition vs abtraction -> turns into a discussion about creationism vs evolution. :D

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 11:33 am
by Jonah Bron
John Cartwright wrote:
VladSun wrote:What about the Darwin's theory? :P
Oh my. A discussion about about abstraction -> turns into a discussion about composition vs abtraction -> turns into a discussion about creationism vs evolution. :D
Spectacular.

Well, that's a really good explanation, Josh. Composition is now another tool under my belt :)

One part is a bit confusing. You're saying that there's a class called "Walk" or something like that, and it's used by multiple classes? How does it handle different walk methods? Settings parameters? Overriding child classes?

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 11:40 am
by josh
VladSun wrote:What about you and your parents :)
I realize its half joking, but..

The whole "instance of" is context sensitive. That is true if the context is lineage. But what if you were comparing social status? You wouldn't say that a nerd is an "instance of" a sports jock. Perhaps this secondary example shows my point, that inheritance locks you into 1 paradigm, 1 boring view on the world.

I don't like the saying "objects model the real world". Instead concepts in our head model the real world, and our software models the concepts in our head. Concepts in our head do not exist in a hierarchy. That's a better way of saying it.

Our lineage is the opposite of a hierarchy. A hierarchy is like a pyramid, a person's lineage is an upside down hierarchy (not a hierarchy, but rather a directed acyclic graph). Your genes are a composition of randomly selected genes from their chromosomes, other than that there's no 'inheritance'. More like:

Code: Select all

array_push( $newGenes, $parentsGenes[rand(1,100)] );
One part is a bit confusing. You're saying that there's a class called "Walk" or something like that, and it's used by multiple classes? How does it handle different walk methods? Settings parameters? Overriding child classes?
Walk could just be an interface, and there could be many classes that implement that strategy. Or you could have 1 strategy, and the strategy itself uses more strategy objects in turn. By configuring your strategy objects with different sub-strategies you can change how it behaves :-) At some point the pattern names become useless and you just think of it all as composition IMO.

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 11:46 am
by VladSun
I was just teasing of course :) I like the idea of having a compoiste DNA :))))

I want to stress on some statements I wrote here and explain them a bit:
IMHO, a namespace should be an unique identifier
I meant "worldwide (pseudo)unique". Something like the MAC address of a NIC.
(I would say max 30% inheritance and min 70% composition).
*max* and *min* used. it may be 0/100, 10/90 or 70/30.

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 12:12 pm
by Jonah Bron
josh wrote:Walk could just be an interface, and there could be many classes that implement that strategy. Or you could have 1 strategy, and the strategy itself uses more strategy objects in turn. By configuring your strategy objects with different sub-strategies you can change how it behaves :-) At some point the pattern names become useless and you just think of it all as composition IMO.
So lets create an example so as to make sure I've got a good understanding of what you're talking about, shall we?

Dog

Code: Select all

class Dog implements FourLegged {
    private $walkStrategy = new FourLeggedWalk();
    public function walk() {
        $this->walkStrategy->walk($this);
    }
    // four legged functions
}
Cat

Code: Select all

class Cat implements FourLegged {
    private $walkStrategy = new FourLeggedWalk();
    public function walk() {
        $this->walkStrategy->walk($this);
    }
    // four legged functions
}
Robot

Code: Select all

class Robot implements TwoLegged {
    private $walkStrategy = new TwoLeggedWalk();
    public function walk() {
        $this->walkStrategy->walk($this);
    }
    // TwoLegged functions
}
FourLegged interface

Code: Select all

interface FourLegged {
    public function liftLeg();
    public function lowerLeg();
    public function moveLegForward();
    public function moveLegBackward();
}
Walk interface

Code: Select all

interface Walk {
    public function walk($object);
}
Two legged walk strategy

Code: Select all

class TwoLeggedWalk implements Walk {
    public function walk(FourLegged $object) {
        $object->liftLeg(0);
        $object->moveLegForward(0);
        $object->moveLegBackward(1);
        $object->lowerLeg(0);
        $object->liftLeg(1);
        // ...
    }
}
Four legged walk strategy

Code: Select all

class FourLeggedWalk implements Walk {
    public function walk(TwoLegged $object) {
        // ...
    }
}

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 12:15 pm
by VladSun
Now josh will tell you not to instantiate objects internally, but pass them:

Code: Select all

$cat = new Cat(new One_of_four_legs_broken_Walk_Strategy());
:P

//offtopic
LOL, this topic is a fun :)

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 12:17 pm
by Jonah Bron
Ah, good point Vlad. Even if it is the same animal, the strategy might change.

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 2:50 pm
by Weirdan
Jonah, your interfaces seems to be for walker collaborators => you're missing basic 'Walking' interface (for consumers):

Code: Select all

interface Walking {
   public function walk($direction);
}
class Dog implements Walking,... {
    public function walk($direction) {
         $this->getWalkingStrategy()->walk($direction);
    }
    // ....
}

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 4:10 pm
by josh
Yeah, what weirdan said. You asked PHP to implement a class instead of an interface, won't compile. More like this:

Code: Select all

// use like this
$dog = new Dog( new Walk_FourLegged );
$robot = new Robot( new Walk_Moonwalk );

class Dog implements Walking, Speaking, Biting
{
 function walk()
 {
  $this->walkStrategy->walk();
 }
 ...
 ....
  function bite()
 {
 }
}

class Robot implements Walking, Killing
{
 function walk()
 {
  $this->moonWalk->walk(); // i set up a setting to tell the walk strategy it should moon walk in particular, lol
 }
}
The important thing is that Dog & Robot do not depend on any particular class, they depend on an interface. They aren't coupled to any class in the system. I mean the part where you say "new new" is coupled to a class, but we've separated the "new new" parts of the code, the "wiring up of the objects" separated from the business logic.

This way our robot can learn more than once dance move ;-) He can stop moon walking and start doing the "krypt walk" at run-time. That is the objects can be re-wired mid-execution.

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 4:39 pm
by Jonah Bron
Okay, and what do the Walk_FourLegged and Walk_Moonwalk classes look like?

BTW, I ended up using composition on a project just today :). Stupid Java wouldn't let me extend Rectangle * mutter mutter * :nono:

Re: Namespaces and abstract class names

Posted: Fri Feb 04, 2011 5:57 pm
by josh

Code: Select all

interface WalkingStrategy
{
 function walk();
}

class Walk implements WalkingStrategy
{
 function walk() {
  $this->pickupLeftLeg();
  $this->moveAndSetLeftLegDown( "6 inches" );
  $this->pickupRightLeg();
  // etc...
 }
}
The interface is used to show which methods we care about in our Walkable classes. pickupRightLeg() wouldn't be a method on the "100 legged super centipede robot walking strategy", lol.

So as you see the best answer to abstract classes & name-spaces is stop using abstract classes ;-) At least if you are trying to maximize extensibility and minimize re-factoring. If you just want the simplest code, inheritance may be best.