PDA

Click to See Complete Forum and Search --> : [RESOLVED] Conditional check vs. Method overriding


tomcatexodus
Aug 28th, 2010, 05:35 AM
I know many of my threads deal with optimization, but I'm trying to broaden my knowledge base of common bottlenecks.

Anyhow, as of currently an application I'm working on makes use of a couple classes I've created.

For simplicity:

abstract class WidgetBase{}

class AlphaWidget extends WidgetBase{}

class BetaWidget extends WidgetBase{}

class GammaWidget extends WidgetBase{}

Now, all is fine and good, my abstract WidgetBase has a nice collection of inherited methods/properties and everything is clean. The issue is though, that GammaWidget is complicating things, as it has an additional property of instance (or index) that adds an additional dimension to the array properties it inherits.

That puts me in the position of having to override all of the otherwise inherited methods to accommodate this difference. Example:

//from WidgetBase, works fine with Alpha and Beta
public function compile(){
foreach($this->data as $name => $value){
//do something
}
}

//and from GammaWidget
public function compile(){
for($i = 0; $i <= $this->instance; $i++){
foreach($this->data[$i] as $name => value){
//do something
}
}
}

My question is, should I maintain my overridden method approach, or add a conditional check on the calling class in the inherited compile() method, and split my code accordingly, keeping both routes in the same inherited method?

Which would be the best practice?

Note: This would apply to about 9 other methods.

kows
Aug 28th, 2010, 11:49 AM
it doesn't really matter. if there will ever be another class like "gammawidget," then it would be better to have it built-in to the parent class. if you're sure there will not, then it really isn't going to make much of a difference. do whichever makes the most sense to you.

tomcatexodus
Aug 28th, 2010, 03:45 PM
Alright, I'll probably leave it as it's own set of methods, as the only large one is the compile() one I've mentioned. (Most others are small setter/getter/query methods)

It seems most logical to do this, but is there anyone whose preference would be otherwise? As a conditional check in a single inherited method, or perhaps a different approach altogether?

Perhaps there is some very minor processing/memory cost advantage if done another way, as the engine wouldn't need to load all the overriding methods. (This is quite a possibility, as I've been running some tests on the usage of my script, and often times there can be up to a few thousand of these GammaWidget-style objects created.)

A better understanding on how the Zend engine handles objects in memory could be an asset here.

kows
Aug 28th, 2010, 04:30 PM
abstract classes are great, but if all of (or most of) the methods that your one class is inheriting need to be overloaded, then you're probably doing something wrong. in that case, the most common methods that need no modification could be within BaseWidget, and then then two new abstract classes -- SimpleCompile and ComplexCompile -- could be built from those. BaseWidget should have the definitions of the methods being used (compile(), for example), but leave the implementation up to the child. then, Gamma extends ComplexCompile and anything else extends SimpleCompile. this is probably what I would do, but I don't know your situation, so I really couldn't say for sure.

however, the method I described above is the implementation of my model classes (based on ORM):
abstract class Model implements Iterator {

final public function __construct(){
// initialization
}

// Factory method
final public function create(){
return new static;
}

// Iterator's methods follow:
final public function rewind(){
$this->_i = 0;
}
final public function current(){
return $this->valid() ? $this : false;
}
final public function next(){
++$this->_i;
}
// etc.

// abstract methods follow:
abstract public function where($pattern, array $values = array());
abstract public function innerJoin($table, $field);
abstract public function orderBy($order);
abstract public function limit($rowcount, $offset = null);
abstract public function find();
abstract public function findOne();
abstract public function count();
abstract public function save();
abstract public function delete();
}
then, the class MySQLModel implements all of the complicated methods, as the differences between MSSQL, MySQL and Oracle can be enough to cause problems.

while it's nice to have optimized, fast code, you really should focus on writing smart, clean, and easy-to-interpret code. if a bottleneck presents itself, you can optimize when you need to. chances are, nothing you're doing is going to make any difference, because the bottleneck may end up being your database connection.

tomcatexodus
Aug 28th, 2010, 05:51 PM
Well, as usual, thank you for your insight kows :)

This project I'm working on deals exclusively with keeping the implementation of it smart, clean, and easy-to-interpret, through the use of a fluent interface for document templating. It's a revamp of the template engine I posted for discussion some time ago.

Since there is only a single class that deviates so heavily from the base, and there is no need in the (foreseeable) future to add further classes, I'll stick with what I have. However, I have considered adding another level of abstract classes, precisely as you explained.

Thanks again kows.