Namespaces and abstract class names
Moderator: General Moderators
- Jonah Bron
- DevNet Master
- Posts: 2764
- Joined: Thu Mar 15, 2007 6:28 pm
- Location: Redding, California
Re: Namespaces and abstract class names
Wait, so the walk strategy keeps track of the leg state, not the Dog/Robot?
Re: Namespaces and abstract class names
Yep, the Strategy object should not know anything about its owner/master
There are 10 types of people in this world, those who understand binary and those who don't
- Jonah Bron
- DevNet Master
- Posts: 2764
- Joined: Thu Mar 15, 2007 6:28 pm
- Location: Redding, California
Re: Namespaces and abstract class names
Ah, I see.
So what about an obvious situation for an abstract class, like the Db library I linked to? Would an abstract class be better in that situation? Or is that subjective?
So what about an obvious situation for an abstract class, like the Db library I linked to? Would an abstract class be better in that situation? Or is that subjective?
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Namespaces and abstract class names
While I agree that interfaces + composition + DI does what inheritance does, plus adds some nice functionality for mixins, multiple inheritance, etc. However, I want to temper Josh's ooh-aah presentation with the fact that (in PHP) simple inheritance solve a lot of common use cases in a very simple way. I advocate composition over inheritance, but I also think people like the Javascript guys have convinced themselves that inheritance is bad because they don't have it.
As an analogy, you could by a car that has an engine included (inherited), or you could by a car that comes with an Engine Injector that creates and puts a new engine into the car every time you want to drive it. Yes, they do the same things. And yes, the Engine Injector potentially could do some cool stuff. But on some level you are just doing more work for the same result.
As an analogy, you could by a car that has an engine included (inherited), or you could by a car that comes with an Engine Injector that creates and puts a new engine into the car every time you want to drive it. Yes, they do the same things. And yes, the Engine Injector potentially could do some cool stuff. But on some level you are just doing more work for the same result.
(#10850)
- Jonah Bron
- DevNet Master
- Posts: 2764
- Joined: Thu Mar 15, 2007 6:28 pm
- Location: Redding, California
Re: Namespaces and abstract class names
So it's like everyone has said so far: composition is good sometimes, and inheritance is good sometimes.
That's interesting Christopher: composition may help us a lot working on <whisper>ProjectX</whisper> *wink wink*
That's interesting Christopher: composition may help us a lot working on <whisper>ProjectX</whisper> *wink wink*
Re: Namespaces and abstract class names
A better analogy is with the inheritance car, to replace the engine you have to replace every other part.Christopher wrote:As an analogy, you could by a car that has an engine included (inherited), or you could by a car that comes with an Engine Injector that creates and puts a new engine into the car every time you want to drive it. Yes, they do the same things. And yes, the Engine Injector potentially could do some cool stuff. But on some level you are just doing more work for the same result.
With the composition car every part is interchangeable on it's own.
"injecting" the engine into the car would not be done by the person using the car, probably it would be done at the factory (some soft of factory object)! It would only need be done once, not every time you instantiate it. You create that factory 1x only and use it millions of times, you don't ever need to worry about the engine again, until you want to.
Although I did say inheritance does provide simpler code, obviously simple is subjective but I see it this way: not having a factory is simpler than having one. However being able to change your engine out easily is also simpler than having to refactor an abstract class. So again, its really subjective. I think what is more objective is composition has more propensity for writing complex programs that follow good practices. Inheritance eventually has to break down, eventually the programmer will put walk(), breathe() & kill() all in one super class, or will duplicate the walk() method. (mixing the responsibilities of animals/robots. That part is objective.
Note though, I'm comparing one vs the other. Nothing wrong with using both on the same project, Nothing "wrong" with inheritance either per se. Its just less robust than composition, therefore lower learning curve.
Either way. The walk strategy could hold a reference back to it's master, but typically would not.Jonah Bron wrote:Wait, so the walk strategy keeps track of the leg state, not the Dog/Robot?
Re: Namespaces and abstract class names
The car analogy is inaccurate. The Car is "instantiated" once at the Car Factory. The engine is injected, along with the other component parts.
The car doesn't get garbage collected when you park it in your garage at night, it still sits there, ready to be driven again the next day.
The other major difference between inheritance and composition is inversion of control. In inheritance, the child class must know what the parent class does, and how it does it (i.e. implementation - violating black-box!) but in composition, the compositing class only needs to know the interface of its dependencies, it doesn't need to know implementation, and the dependency doesn't need to know anything about the classes it will be used in. Indeed it doesn't even know which classes it will be used in.
Also on the animal/walk example. What if, at runtime, we decide that the 4 legged animal suddenly grows an extra pair of legs? We can inject a different "Walker" object. If we were using inheritance, that can't happen and we'd need to change code to break the inheritance tree.
The car doesn't get garbage collected when you park it in your garage at night, it still sits there, ready to be driven again the next day.
The other major difference between inheritance and composition is inversion of control. In inheritance, the child class must know what the parent class does, and how it does it (i.e. implementation - violating black-box!) but in composition, the compositing class only needs to know the interface of its dependencies, it doesn't need to know implementation, and the dependency doesn't need to know anything about the classes it will be used in. Indeed it doesn't even know which classes it will be used in.
Also on the animal/walk example. What if, at runtime, we decide that the 4 legged animal suddenly grows an extra pair of legs? We can inject a different "Walker" object. If we were using inheritance, that can't happen and we'd need to change code to break the inheritance tree.
Re: Namespaces and abstract class names
Dependency injection is a different topic from composition.
The ability to inject an engine into your car doesn't rule out the car giving itself a default engine. Whether the car sets it's own engine or a factory does it, is irrelevant (to this discussion at least). As long as its collaborating with another object, instead of with a super-class. Your object could grab the strategy from a global variable, it's not advisable but its still composition.
Aside from using a factory to instantiate it, there is no difference to the user of the class. I think its accurate. "buying the car" from the factory in real life is analogous to "writing the code for the factory class" in your program. You only do it once. From then on out you just take the factory object and ask for your car. (The fact its injecting an engine isn't of any importance really...).
Composition + Inheritance on same project = You can follow the single responsibility principle
Inheritance only = You cannot follow the single responsibility principle.
The ability to inject an engine into your car doesn't rule out the car giving itself a default engine. Whether the car sets it's own engine or a factory does it, is irrelevant (to this discussion at least). As long as its collaborating with another object, instead of with a super-class. Your object could grab the strategy from a global variable, it's not advisable but its still composition.
Aside from using a factory to instantiate it, there is no difference to the user of the class. I think its accurate. "buying the car" from the factory in real life is analogous to "writing the code for the factory class" in your program. You only do it once. From then on out you just take the factory object and ask for your car. (The fact its injecting an engine isn't of any importance really...).
Composition + Inheritance on same project = You can follow the single responsibility principle
Inheritance only = You cannot follow the single responsibility principle.
Re: Namespaces and abstract class names
Jenk wrote:Or get rid of the "abstract" bit of it, and use it as a composite in all "child" classes
I am seriously of the opinion these days that abstract classes are foul, and the only thing that should ever be abstracted is an interface (which is redundant in PHP anyway, as of course it is dynamic - happy days!)
Code: Select all
class Object_Abstract
{
public function setup($config)
{
foreach ($config as $property => $value)
{
if (property_exists($this, $property))
{
$this->{$property} = $value;
}
else
{
throw new \InvalidArgumentException('Property ('.$property.') does not exist.');
}
}
}
}There are 10 types of people in this world, those who understand binary and those who don't
Re: Namespaces and abstract class names
That's a bit of an interesting example. The usage seems to be something like:
Why not just:
or better yet:
Code: Select all
$config = array("foo" => "bar", "baz" => "blah");
$something = new Something();
$something->setup($config);Code: Select all
$something = new Something();
$something->foo = "bar";
$something->baz = "blah";Code: Select all
$something = new Something("bar", "blah");Re: Namespaces and abstract class names
as for DI being a separate topic, yes it is, but if using Inheritance, there is no possible way to change the dependency without changing the inheritance tree. The point I was getting at, is that it is bad practice to depend on implementation (something you must and can only do with Inheritance) vs depending only on the role/interface which allows anything that implements that role/interface to be used.
Re: Namespaces and abstract class names
$foo and $bar may be private/protected.Jenk wrote:Why not just:
Code: Select all
$something = new Something(); $something->foo = "bar"; $something->baz = "blah";
A better "setupable" object would be:
Code: Select all
class Object_Abstract
{
public function setup($config)
{
foreach ($config as $property => $value)
{
if (method_exists($this, 'set' . ucfirst($property)))
{
$this->{'set' . ucfirst($property)}($value);
}
elseif (property_exists($this, $property))
{
$this->{$property} = $value;
}
else
{
throw new \InvalidArgumentException('Property ('.$property.') does not exist.');
}
}
}
}We had a related discussion here:Jenk wrote:or better yet:Code: Select all
$something = new Something("bar", "blah");
viewtopic.php?f=19&t=126953
Also :
Code: Select all
public function setup($config)
{
...
$this->fireEvent('reconfigured', $this, $config);
}There are 10 types of people in this world, those who understand binary and those who don't
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
Re: Namespaces and abstract class names
I think these statements are erroneous. First, Inversion of Control and black-box are two different things that you conflate here.Jenk wrote:The other major difference between inheritance and composition is inversion of control. In inheritance, the child class must know what the parent class does, and how it does it (i.e. implementation - violating black-box!) but in composition, the compositing class only needs to know the interface of its dependencies, it doesn't need to know implementation, and the dependency doesn't need to know anything about the classes it will be used in. Indeed it doesn't even know which classes it will be used in.
Second, a child class need not know any more about methods it inherits than the interface. This is no different than what is known about a method in a composited object. You can choose to look at the source of either or not. You can choose to use or replace the methods of either, or not. You don't know anything about the implementation of PHP's many built-in classes, yet can happily extend them knowing only their interfaces. Similarly, a class can be provided access to the properties of both inherited classes and composited objects, or not.
My point above was only that for many common use cases inheritance is the simplest solution -- involving only two additional words in a class file.
(#10850)
Re: Namespaces and abstract class names
I knew that would happen, I'm not talking of "Inversion of Control" (i.e. "Dependency Injection") I'm stating the the control of what is implemented is inverted (i.e. the literal meaning of the control has been inverted
) in that the "parent" becomes the "child"/dependent.
Re: Namespaces and abstract class names
Subclasses do know their superclass' implementation. Try to have both classes use variables & methods with the same name, you don't have to worry about that crap if you don't use inheritance 
@Vlad, OK, but you could have a class called Config and just pass the whole config object. All that logic would live in only the config class, instead of asking your compiler to make it available globally on all classes. When classes need to be configured they collaborate with a config object, or the config object collaborates with them. Either the config object can be injected into the "main object". Or the config object could be passed an instance to the "main object", and would subsequently call a bunch of setter commands on the "main object" to set it up. Your config objects would be like data mappers.
The problem with your abstraction, again, is you may have classes that need to implement it differently. You did conjure up a low risk example of using abstraction but I'm sure I still see risk in coding that way.
@Vlad, OK, but you could have a class called Config and just pass the whole config object. All that logic would live in only the config class, instead of asking your compiler to make it available globally on all classes. When classes need to be configured they collaborate with a config object, or the config object collaborates with them. Either the config object can be injected into the "main object". Or the config object could be passed an instance to the "main object", and would subsequently call a bunch of setter commands on the "main object" to set it up. Your config objects would be like data mappers.
The problem with your abstraction, again, is you may have classes that need to implement it differently. You did conjure up a low risk example of using abstraction but I'm sure I still see risk in coding that way.