Who fancies a community effort to write a book?

Where we keep all the boring tidbits about the PHPDN site, the news, and what not.

Moderator: General Moderators

Postby Chris Corbyn » Sat Sep 02, 2006 7:20 am

jmut wrote:Hi,
I think The Decorator pattern explained at

http://phpbook.quantum-star.com/doku.ph ... _decorator

has some design flaws...which more or less defeats the purpose of the design pattern. Since, I kind of don't want to search in 13 page thread...has this issue been discussed?
If not...I will provide a version I believe is more accurate.


Go for it :) By the way, if you joined the Community Composition Members group you wouldn;t need to search a 13 page thread since we have a forum here... ;)
User avatar
Chris Corbyn
Breakbeat Nuttzer
 
Posts: 13098
Joined: Wed Mar 24, 2004 8:57 am
Location: Melbourne, Australia

Postby jmut » Sat Sep 02, 2006 8:56 am

d11wtq wrote:
jmut wrote:Hi,
I think The Decorator pattern explained at

http://phpbook.quantum-star.com/doku.ph ... _decorator

has some design flaws...which more or less defeats the purpose of the design pattern. Since, I kind of don't want to search in 13 page thread...has this issue been discussed?
If not...I will provide a version I believe is more accurate.


Go for it :) By the way, if you joined the Community Composition Members group you wouldn;t need to search a 13 page thread since we have a forum here... ;)


ok, where do I post my solution. is here ok....or there is something on the patterns site..I don't see
jmut
Forum Regular
 
Posts: 945
Joined: Tue Jul 05, 2005 3:54 am
Location: Sofia, Bulgaria

Postby jmut » Sat Sep 02, 2006 9:02 am

Oh well, I will post it here for now..should not crash to forum or anything.

Damn, it is hard to express yourself.
This is more or less my first try to do thorough explanation of my thoughts :)
- writing an article sort of speech.
Hopefully I made it easy to read and comprehendable but you are the one to judge this.


Why Decorator Pattern?
Decorator pattern comes from the paradigm in OOP that each object should do
only what it is supposed to do. Just like Unix, do small and simple stuff and do it right.
To do complex stuff combine small elements and you get solid functionality that is
easy to maintain.

Our Scenario:
We have titles, pageFooters, and we have getData() to get the text of those...but...
What, if you want to log each time you get page's title - for whatever weird reason that is?
You don't add log() method in the title class because this is totally different functionality
that has nothing to do with titles (low cohesion).
For more on that take a look at.

http://en.wikipedia.org/wiki/Cohesion_% ... science%29

Another reason is to avoid duplication and keep easy maintainance of your code.

Lets take a look at the UML diagram ( http://up.drun.net/files/decorator.png ) we have and try explain the Decorator pattern.
I have provided the code for this UML diagram so feel free to use either.


Basic legend:
~ -> means implementation of some abstract method/property
- -> private method/property
+ -> public method/property
# -> protected method/property


What is "client code"?
Since I use the term here and there I would like to explain what I reffer to as client code
to avoid all confusion for those who does not know.
Lets take PEAR for example...it is library or whatever. The client code will be any
code that make use of PEAR library. like PEAR::isError or whatever.
If we say that we are building the library....we will strive to hide data as possible
to the client code, so we have greater control over our library. e.g. if our library (class(s))
have defined all methods as public...this will be total disaster as we cannot safely
change/refactor/improve our library - at anytime we might break someons implementation(client code).


UML explanation: ( http://up.drun.net/files/decorator.png )

At the top we have the interface pageElement. This is the key component.
Putting decoration asside for a minute we will have pageElement interface
and some concrete implementations that will... well..implement it (pageFooter,Title)

The interface is there to show what this class(s) (the implementations - Title,PageFooter) are intended
to do. You just build the object and use any public methods that the interface defines.
No methods not defined in the interface!!...all you could use on an object is described in the interface.
This is why it is an interface.

Now what happens if you need some more functionality, like logging for example when title data is retrieved.
Well, you build abstract decorator and then do some implementations of this
decorator (LogGetData,Color,Underline).

The abstract decorator should implement the pageElement interface because
this is what we are going to decorate after all, and we want to obey to this functionality.
The decorations happens transaprantly to the client code!!! No explicit calls to decorators are made!!!

Again, all decorator implementations(LogGetData,Color,Underline) have ONLY public methods
defined by the interface!!! Otherwise we will end up having $title->log(); which defeats
the purpose of the pattern.


Key moments:
- one top interface to which everyone obeys(pageElement)
- abstract decorator that uses composition... Stores pageElement implementation (decorated afterwards using cascade calls)
- decorator implementations (LogGetData,Color,Underline) - also having only publics defined
by the interface(this ensures you don't break the client code if you decide to remove the decoration at some point).
- each public method in the decorator ultimately deligates/returns data so a cascade call occurs.


Pros:
- strong cohesion http://en.wikipedia.org/wiki/Cohesion_% ... science%29
- flexible factory of objects with different functionality (single point..easy to follow)
- easy code maintanance - lots of simple classes doing distinct stuff, and doing it good.
- avoids lots of duplication - avoids methods like colorLogUnderline()

Cons:
- all public methods of the interface should be implemented in each decorator implementation (if only to just deligatte to parent).
Meaning too many public methods are getting harder to maintain. It is time to rethink your objects (maybe they do more than they should)


Conclustion...what was achieved:

Lets say someone should use this class/library we just build.
Our documentation will througohly describe the interface pageElement,
mentioning that there are decorators to it...and can use the *_Factory class(s)
to build fancy objects.

So the devoloper will be like:
aha Decorator - I know the idea of this...let see how can I use it. Ok, some factory
classes, good I don't need to look at all those decoratores one by one to know how to build fancy stuff.

And what can I do with the fancy objects? Let me check the interface...aha getData()
Cool, not much but with decoration it will come out to be one fancy getData :) - solid.

Hence, no need to know specifics of decorators! Know what an object could do (the interface)
so no need to look at source code and stuff. one factory class to learn to know
how to build all kind of fancy combinations.

Syntax: [ Download ] [ Hide ]
<?php



/**

 * Interface two which all should obey.

 * Client (developer) needs to know only these public methods

 * to make use of the object(s).

 * This could be abstract class as well.

 * @abstract

 */


interface PageElement

{

    public function getData();

}





abstract class PageElementDecorator implements PageElement

{



    /**

     * This is an implementation object of PageElement. (could be Title,PageFooter..etc)

     * The object we are going to decorate.

     *

     * @var PageElement

     */


    protected $element = null;



    public function __construct(PageElement $element)

    {

        $this->element = $element;

    }



}





class PageFooter implements PageElement

{

    private $content = '';



    public function __construct($content) {

        $this->content = $content;

    }



    public function getData() {

        return $this->content;

    }



}





class Title implements PageElement

{

    private $text = '';



    public function __construct($text)

    {

        $this->text = $text;

    }



    public function getData() {

        echo "Getting ".__CLASS__." data\n";

        return $this->text;

    }



}









class Color extends PageElementDecorator

{

    private $colorName = '';



    public function __construct(PageElement $element,$colorName = 'defaultColor')

    {

        parent::__construct($element);

        $this->colorName = $colorName;



    }



    public function getData()

    {

        $data = $this->element->getData();

        //do the decoration (coloring)    and pass data.

        echo "coloring the data with:".$this->colorName."\n";

        //return data...so others can decorate or use.

        return $data;

    }

}





class LogGetData extends PageElementDecorator

{

    public function getData()

    {

        //do Some loging before getting data    using   log()

        echo "doing some logging before Getting Data\n";

        $data = $this->element->getData();

        //..or maybe after that log()

        //..or why not both...to measure performance for example?

        echo "doing some logging after Getting Data\n";



        return $data;

    }



    private function log()

    {

        //log stuff

    }

}





class Underline extends PageElementDecorator

{

    public function getData()

    {

        $data = $this->element->getData();

        //underline data

        echo "Underlining data\n";

        $data = '<span style="text-decoration: underline;">'.$data.'</span>';

        return $data;

    }

}





/* @var PageElement $title*/





//$title = new Color(new Underline(new LogGetData(new Title("PageTitleText"))),"black");



$title = Title_Factory::build("PageTitleText",'undelinedBlackColeredWithLogging');

echo $title->getData();





/**

 * Since we want to be as flexible as possible we provide a factory class

 * to build our fancy objects for us.

 * You will probably think of better way than 'undelinedBlackColeredWithLogging'

 * string but the goal here is to hide again the implementation.

 * This way the client code does not know that the underlining class is named

 * "Underline"....hence we can safely do refactoring of classes and stuff..and client

 * code will still work.

 *

 *

 * e.g   a simple refactoring will be renaming class Color...as this name does

 * not really represent the purpose of the class.

 * We rename it to "ColorDecorator" for example...but notice how we need to only

 * change it in the switch statement, and of course the class declaration itself!!!

 * We don't care who is using it (the client code)...we know it does the same thing

 * and it works.

 *

 */


class Title_Factory

{

    private function __construct() {}

    private function __clone() {}



    static public function build($titleText,$titleType = 'default') {

        switch ($titleType) {

                case 'undelinedBlackColeredWithLogging':

                        $title = new Color(new Underline(new LogGetData(new Title($titleText))),"black");

                        break;

                default:

                    $title = new Title($titleText);

                        break;

        }

        return $title;

    }

}





?>
jmut
Forum Regular
 
Posts: 945
Joined: Tue Jul 05, 2005 3:54 am
Location: Sofia, Bulgaria

Postby Chris Corbyn » Sat Sep 02, 2006 9:02 am

*cough* wiki *cough* ;)

You can just edit my post, it won't hurt anything ;)
User avatar
Chris Corbyn
Breakbeat Nuttzer
 
Posts: 13098
Joined: Wed Mar 24, 2004 8:57 am
Location: Melbourne, Australia

Postby jmut » Sat Sep 02, 2006 9:11 am

d11wtq wrote:*cough* wiki *cough* ;)

You can just edit my post, it won't hurt anything ;)

I would rather people have a look at it, say it sucks or it is better than the old one
and then change :)

P.S. oh well, I guess it is just that I don't feel ok with wiki :)
jmut
Forum Regular
 
Posts: 945
Joined: Tue Jul 05, 2005 3:54 am
Location: Sofia, Bulgaria

Postby RobertGonzalez » Sat Sep 02, 2006 6:48 pm

The purpose of the wiki is to allow for others to make necessary changes. Post there. Also, look into joining the Community Composition Contributors group in our forums. To do that, click on the Usergroups links at the top of any forum page (or you can get there by clicking here). Select the Community Composition Contributors group, click View Information and then choose subscribe.
User avatar
RobertGonzalez
Site Administrator
 
Posts: 14291
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Postby jmut » Sun Sep 03, 2006 1:42 am

Everah wrote:The purpose of the wiki is to allow for others to make necessary changes. Post there. Also, look into joining the Community Composition Contributors group in our forums. To do that, click on the Usergroups links at the top of any forum page (or you can get there by clicking here). Select the Community Composition Contributors group, click View Information and then choose subscribe.

ok, I added it to wiki.
Call me stupid, but I don't see how to subscribe for this group :roll: There is no such link or anything.
Also, would be great if the UML diagramm could be somehow moved to a more permanent place....because I don't know for how long it will stay there.
jmut
Forum Regular
 
Posts: 945
Joined: Tue Jul 05, 2005 3:54 am
Location: Sofia, Bulgaria

Postby Chris Corbyn » Sun Sep 03, 2006 6:26 am

jmut wrote:Call me stupid, but I don't see how to subscribe for this group :roll: There is no such link or anything.


You click "View" and then "Subscribe". I'll just add you manually anyway ;)
User avatar
Chris Corbyn
Breakbeat Nuttzer
 
Posts: 13098
Joined: Wed Mar 24, 2004 8:57 am
Location: Melbourne, Australia

Postby RobertGonzalez » Sun Sep 03, 2006 10:49 pm

jmut wrote:Call me stupid, but I don't see how to subscribe for this group :roll: There is no such link or anything.

d11 is taking care of it for you, but was this instruction not clear?
Everah wrote:Also, look into joining the Community Composition Contributors group in our forums. To do that, click on the Usergroups links at the top of any forum page (or you can get there by clicking here). Select the Community Composition Contributors group, click View Information and then choose subscribe.
User avatar
RobertGonzalez
Site Administrator
 
Posts: 14291
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Postby jmut » Tue Sep 05, 2006 2:20 am

Everah wrote:
jmut wrote:Call me stupid, but I don't see how to subscribe for this group :roll: There is no such link or anything.

d11 is taking care of it for you, but was this instruction not clear?
Everah wrote:Also, look into joining the Community Composition Contributors group in our forums. To do that, click on the Usergroups links at the top of any forum page (or you can get there by clicking here). Select the Community Composition Contributors group, click View Information and then choose subscribe.

instruction was crystal clear...but
when I got in there there was just no subscribe button....no idea if it was disabled...session gone bad or whatever just don't know.
Next day I think...I went there again and there was the subscribe button...clicked, pending.... d11 wrote he will take care of that manually...and I guess he just accepted my subscription then.
Cheers
jmut
Forum Regular
 
Posts: 945
Joined: Tue Jul 05, 2005 3:54 am
Location: Sofia, Bulgaria

Postby RobertGonzalez » Tue Sep 05, 2006 8:38 am

Ok, I just wanted to know since I am a member of almost all of the groups so I can't subscribe. I just wanted to make sure I gave you the right instructions.
User avatar
RobertGonzalez
Site Administrator
 
Posts: 14291
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Postby Maugrim_The_Reaper » Mon Sep 11, 2006 2:50 am

Basically a quick note...

As of 8:46 am, 11 Sep 2006, Maugrim has returned from limbo. Yep, I even have full internet access once again. Currently clearing through my email (two months worth!), recovering from a weekend party celebrating the end of those examinations I was taking last week (and studying for between work for the last two months), and getting to grips with the accumulation of mail that the postman managed to cram into my postal slot.

I am about three months out of touch, completely unaware of most things that have been happening in these here PHP parts. I'll be my usual forum slave self in about an hour. Good to be back - the internet withdrawel was a killer ;).
Pádraic Brady

http://blog.astrumfutura.com
http://www.survivethedeepend.com
Zend Framework Community Review Team
Zend Framework PHP-FIG Representative
User avatar
Maugrim_The_Reaper
DevNet Master
 
Posts: 2704
Joined: Tue Nov 02, 2004 6:43 am
Location: Ireland

Postby n00b Saibot » Mon Sep 11, 2006 3:48 am

welcome back, Maugrim. I'm sure guys here would hav missed the Irish humor all these days :)
User avatar
n00b Saibot
DevNet Resident
 
Posts: 1452
Joined: Fri Dec 24, 2004 3:59 am
Location: Lucknow, UP, India

Postby RobertGonzalez » Mon Sep 11, 2006 7:06 pm

Welcome back Maugrim. I was beginning to worried about you.
User avatar
RobertGonzalez
Site Administrator
 
Posts: 14291
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Postby Oren » Tue Sep 12, 2006 9:57 am

Good to hear from you, I have been waiting for new design patterns on your site, keep on the great work :wink:
User avatar
Oren
DevNet Resident
 
Posts: 1640
Joined: Fri Apr 07, 2006 5:13 am
Location: Israel

PreviousNext

Return to Site News

Who is online

Users browsing this forum: Exabot [Bot] and 1 guest