Function reuse / duplication
Moderator: General Moderators
Function reuse / duplication
I'm pretty new to OO especially in PHP. I touched on it a couple of years ago on a course, but never really tried programming it beyond what the course required, anyway now I've started trying to follow OO concepts with my PHP coding, to tidy it up and to make it more flexible, and I came up with this problem/question
Say you have a function that carries out a specific task, and this task is common, something like recursively removing a directory.
Next, lets say you have 2 unrelated classes with no common parent, but both need to be able to remove a directory.
Would you just copy and paste the same function into both classes, or try to build some kind of Utility class that contains stuff like this and just use it like a function library?
Is it a question of personal style or is there design principles behind the one or the other of these. (or a different option)
Say you have a function that carries out a specific task, and this task is common, something like recursively removing a directory.
Next, lets say you have 2 unrelated classes with no common parent, but both need to be able to remove a directory.
Would you just copy and paste the same function into both classes, or try to build some kind of Utility class that contains stuff like this and just use it like a function library?
Is it a question of personal style or is there design principles behind the one or the other of these. (or a different option)
Welcome to the world of OO 
I'd possibly create a directory object, which will contain not only the ability to remove the directory, but other functionality such as listing the contents, and so forth. I would then pass this object as a parameter to the object that require any directory functionality.
I'd possibly create a directory object, which will contain not only the ability to remove the directory, but other functionality such as listing the contents, and so forth. I would then pass this object as a parameter to the object that require any directory functionality.
Code: Select all
$object = new SomeObject();
$object->addDirectory(new Directory('/path/to/some/dir'));
// $object is now able to use the Directory object to manipulate '/path/to/some/dir' directory.- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
You ended up with a valid solution
, so all I'll do is elaborate a little.
A key thing in OOP is to avoid code duplication. If you were to copy a function across a dozen classes, and you discovered later there was a bug in that code then you would be faced with making 12 edits instead of just one. Of course by that stage you may not know how many copies exist, and where they are in your applications (or even how many applications!).
Avoiding duplication isn't too difficult. If you encounter a task which is Class A, and later you realise you need to use it in Class B and Class C, then a common "refactoring" is to extract a new class which contains the common task. This is where your tentative solution hit the mark almost dead on. You can go a step further by remembering a class should be specific - so while a Utility class would work, as it gathers responsibilities and methods (functions) you'll realise it has lost a specific purpose. A good thing is to take a task, give it a name, and slot into a class which seems related - perhaps DirectoryManager for example where you can bundle general directory management code.
After that it's simply a matter of getting your new Utility class into the other two classes where it can be used. This is another topic, but a common solution is to pass it in as a constructor parameter, or through a setter method; example in PHP5:
There are other options where all this parameter passing is getting too numerous like the Registry Design Pattern, Singleton, etc. But the above is the most basic type of usage.
You seem to be moving in the right direction for OOP - so good luck on that
.
A key thing in OOP is to avoid code duplication. If you were to copy a function across a dozen classes, and you discovered later there was a bug in that code then you would be faced with making 12 edits instead of just one. Of course by that stage you may not know how many copies exist, and where they are in your applications (or even how many applications!).
Avoiding duplication isn't too difficult. If you encounter a task which is Class A, and later you realise you need to use it in Class B and Class C, then a common "refactoring" is to extract a new class which contains the common task. This is where your tentative solution hit the mark almost dead on. You can go a step further by remembering a class should be specific - so while a Utility class would work, as it gathers responsibilities and methods (functions) you'll realise it has lost a specific purpose. A good thing is to take a task, give it a name, and slot into a class which seems related - perhaps DirectoryManager for example where you can bundle general directory management code.
After that it's simply a matter of getting your new Utility class into the other two classes where it can be used. This is another topic, but a common solution is to pass it in as a constructor parameter, or through a setter method; example in PHP5:
Code: Select all
class App_DirectoryManager
{
public function removeRecursive($directory)
{
// Remove a directory tree from the file system recursively.
}
}
class App_Cache
{
protected $cacheDirectory = '';
protected $dirManager = null;
public function __construct($cacheDirectory, App_DirectoryManager $manager)
{
$this->dirManager = $manager;
$this->cacheDirectory = $cacheDirectory;
}
}
// or
class App_Cache
{
protected $cacheDirectory = '';
protected $dirManager = null;
public function __construct($cacheDirectory)
{
$this->cacheDirectory = $cacheDirectory;
}
public function setDirectoryManager(App_DirectoryManager $manager)
{
}
}You seem to be moving in the right direction for OOP - so good luck on that
Re: Function reuse / duplication
A utility class (or some call a master class) is not OOP. If you have to put this method into two classes then you probaby are not building your classes correctly.Kadanis wrote:Would you just copy and paste the same function into both classes, or try to build some kind of Utility class that contains stuff like this and just use it like a function library?
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
You really have two main options -- extension and composition:
The both have there advantages ... the main benefit to Composition is that you can change which removeRecursive() method is used at run-time.
Code: Select all
class App_DirectoryManager
{
public function removeRecursive($directory)
{
// Remove a directory tree from the file system recursively.
}
}
// Extension
class MyClass extends App_DirectoryManager
{
// inherits App_DirectoryManager methods
function myfunction($directory)
{
$this->removeRecursive($directory)
}
}
// Composition
class MyClass
{
var $dir_mgr;
// composite App_DirectoryManager object
function __construct($dir_mgr)
{
$this->dir_mgr = $dir_mgr;
}
function myfunction($directory)
{
$this->dir_mgr->removeRecursive($directory)
}
}(#10850)
In this context...Maugrim_The_Reaper wrote:.....You can go a step further by remembering a class should be specific - so while a Utility class would work, as it gathers responsibilities and methods (functions) you'll realise it has lost a specific purpose. A good thing is to take a task, give it a name, and slot into a class which seems related - perhaps DirectoryManager for example where you can bundle general directory management code.
....
A keyword for this would be high cohesion http://en.wikipedia.org/wiki/Cohesion_( ... r_science)
Another key word is low coupling
This is what it is all about
Having simple objects doing specific/related tasks only (high cohesion) and at the same time have these as independant as possible (low coupling) to promot reusability etc.
That is why Utility class is not a great idea...doing all kind of things.
Have fun.
- Ollie Saunders
- DevNet Master
- Posts: 3179
- Joined: Tue May 24, 2005 6:01 pm
- Location: UK
Don't
Repeat
Yourself - that means copy and paste is never the answer.
Repeat
Yourself - that means copy and paste is never the answer.
I've read through and followed up on your responses. Thanks for all the input. I'm sure its going to take some time for me to get my head round it all.
Basically, the built in PHP Directory class doesn't seem to work (probably the 5.0.4 thing mentioned earlier), so I've settled on grouping only directory specific functions into a DirectoryManager class. Like Maugrim suggested.
I've then replaced all occurences of the function (the recursive remove directory) with an instance of the class DirectoryManager (using composition) and called its class function remove(). I've also bundled in functions for listing, counting and retrieving directory contents and replaced those as well, but keeping it specific to directory functions.
I hope this is the right thing to do
it seems to have removed quite a lot of duplicated code and, over time, I hope to replace more in the same way by creating more specific yet reusable classes.
Thanks again for all the help, I think its a long old road though
Basically, the built in PHP Directory class doesn't seem to work (probably the 5.0.4 thing mentioned earlier), so I've settled on grouping only directory specific functions into a DirectoryManager class. Like Maugrim suggested.
I've then replaced all occurences of the function (the recursive remove directory) with an instance of the class DirectoryManager (using composition) and called its class function remove(). I've also bundled in functions for listing, counting and retrieving directory contents and replaced those as well, but keeping it specific to directory functions.
I hope this is the right thing to do
Thanks again for all the help, I think its a long old road though
- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
I think the thread threw a lot of good principles and terms at you - that what you get for posting to the Theory and Design thread
. You'll find that as you continue to practice OOP these sorts of decisions will quickly become habits. The cool thing is that OOP as a skill is language independent, so you could put your future experience to good use in most other languages outside PHP.
Your own observation that duplicated code has been removed shows your change has has a desireable effect - stick with it and don't be afraid to experiment
. And of course always feel free to throw any questions out way
.
Your own observation that duplicated code has been removed shows your change has has a desireable effect - stick with it and don't be afraid to experiment