cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Daniel Fagerstrom <>
Subject Re: [RT] composition vs. inheritance in blocks
Date Sun, 03 Apr 2005 12:56:02 GMT
Reinhard Poetz wrote:
> Daniel Fagerstrom wrote:
>> Reinhard Poetz wrote:

>>> I think I got the idea. Personally, I would solve this by 
>>> composition; the profiling is just another reference of the block. Of 
>>> course, as Stefano said, blocks have to be designed for this. If the 
>>> application block hasn't factored out the profile aspect, then you 
>>> can't replace implementation A by implementation B:
>>> --------------------------------------------------------------------------- 
>>> "Application block" (to be reused in many projects)
>>> --------------------------------------------------------------------------- 
>>> <block xmlns=""
>>>  id="">
>>>   <name>Application block</name>
>>>   <requirements>
>>>     <requires interface=""
>>>       name="skin"
>>>       default=""/>
>>>     <requires 
>>> interface=""
>>>       name="profile"
>>>       default=""/>
>>>     <requires interface=""
>>>       name="portal"
>>>       default=""/>
>>>   </requirements>
>>> </block>
>> It would work, but to achieve what I did in a few sitemap lines 
>> (above) you have to create and deploy a special MyProfile block, and 
>> as I just wanted to override a few things in my customized profile I 
>> have to extend the original profile from the Portal block in some way. 
>> In the sitemap in MyProfile you have to write  a copy of the profiles 
>> section in the Portal block:
>> MyProfile sitemap
>> -----------------
>> ...
>> <profiles>
>> <copletbasedata-load 
>> uri="blocks:/profile/load-global-profile?profile=copletbasedata"/>
>> <copletdata-global-load 
>> uri="blocks:/profile/load-global-profile?profile=copletdata"/>
>> <copletdata-role-load 
>> uri="blocks:/profile/load-role-profile?profile=copletdata"/>
>> <copletdata-user-load 
>> uri="blocks:/profile/load-user-profile?profile=copletdata"/>
>> <copletinstancedata-global-load 
>> uri="blocks:/profile/load-global-profile?profile=copletinstancedata"/>
>> <copletinstancedata-role-load 
>> uri="blocks:/profile/load-role-profile?profile=copletinstancedata"/>
>> <copletinstancedata-user-load 
>> uri="blocks:/profile/load-user-profile?profile=copletinstancedata"/>
>> <copletinstancedata-user-save 
>> uri="blocks:/profile/save-user-profile?profile=copletinstancedata"/>
>> <layout-global-load 
>> uri="blocks:/profile/load-global-profile?profile=layout"/>
>> <layout-role-load 
>> uri="blocks:/profile/load-role-profile?profile=layout"/>
>> <layout-user-load 
>> uri="blocks:/profile/load-user-profile?profile=layout"/>
>> <layout-user-save 
>> uri="blocks:/profile/save-user-profile?profile=layout"/>
>> </profiles>
>> ...
>> <pipeline>
>>  <match pattern="profile/load-user-profile">
>>   ...
>> </match>
>> Here the blocks protocol is supposed to first look in the own sitemap 
>> (and find "load-user-profile") before it asks the super block. As you 
>> can see you need a copy of the profiles section of the sitemap booth 
>> in Portal and in MyProfile. 
> No, you don't. The block "portal" only contains pipelines calls which 
> the block "profile" provides in its sitemap:
> Portal block
> ------------
> - requires "MyProfile" that implements "profile"
> <profiles>
>  <copletbasedata-load
>   uri="blocks:profile:/load-global-profile?profile=copletbasedata"/>
>  <copletdata-global-load
>   uri="blocks:profile:/load-global-profile?profile=copletdata"/>
>   ..
> </profiles>
> (After reading Stefano's mail I found a mistake in my examples: The 
> block name is a sub-protocol and not part of the path.)
> You can have one block that provides default pipelines, let's call it 
> "profile-default":
> "profile-default"
> -----------------
> - implements "profile"
> <map:match pattern="load-global-profile">
>  ...
> </map:match>
> If you need special behaviour in your _custom_ profile block, you extend 
> the "profile-default" block and override _only_ those parts that you 
> want to see changed. In your custom portal block ("MyPortal") you change 
> the requirement from "profile-default" to "MyProfile" and you're done.
> "MyProfile"
> -----------
> - extends "profile-default"
>> And you define and deploy small blocks for each aspect you want to 
>> override in the original block. The behaviour of an actual application 
>> will be spread out in all these small extended blocks. I found it 
>> clumsy, complicated and burocratic compared to the simple sitemap 
>> based extension mechanism I used in my example.
> IIUC your point is that how your application works is spread over to 
> many blocks. Maybe you're right but I don't think so, at least the 
> examples we talked about here are overly complex using


Ok, accepting that we get a number of small blocks, I still think that 
you miss things in your example by not using polymorphism.

Whithout knowing much about the portal, it seem to me that it would more 
natural to let the Profile interface be about an actual profile rather 
than about a number of pipelines that you could use for building a 
profile. A DefaultProfile implementation could (and probably should) 
have a number of pipelines that makes default configuration content 
avaliable and overidable and that are used for building the profile. But 
if we want to actually build easy reusable components the interface 
should not be that fat and specific.

If the DefaultProfile is built this way, really polymorphic (single) 
inheritance will reduce the amount of copying, compared to pure composition.

>>> What I do like is <mount uri-prefix="" src="blocks://portal"/> which 
>>> makes it explicit what a block exports. I'm not sure about why this 
>>> has to be a "two way contract".
>> It must be a two way contract, as "extend and overide" is a two way 
>> contract. If you have it one way you end up having to copy everything 
>> that is an agregate of functionality as in the profile example above.
> Yes, if something isn't designed for reusability, then you have to copy 
> it. If you design for reusablity, you don't have to copy services.

Aggregated services requires real polymorphism, if you don't want to 
copy the sitemap rule or code that does the actual composition.


> I think we should stop the discussion at this point for now (I don't 
> think that anybody can follow it anymore). IIUC everything you proposed 
> can be added in a backwards-compatible way to the existing proposal. But 
> I'm confident we don't need it ;-)

Yes, we obviously not getting anywher, so lets move on and let us design 
really polymorphic blocks with sigle inheritance.

>> Also, I'm intersted in your view about how to actually use the blocks 
>> in an application.

> I can think of many scenarios where blocks make sense. We already talked 
> abut them in this discussion (skinning, profiles, easy deployment, easy 
> development, ...). Does this answer your question or is it too general.

I wouldn't have parcipated in this discussion if I didn't found blocks 
usefull ;)

My question is a serious and IMO important one. If a user is going to 
build an own portal for his/her company and is going to base this on the 
portal block, how will he/she do this. What will the main sitemap look 
like, the deployment configuration etc. In the same way that we needed 
to write example block.xml and block sitemaps, to get better 
understanding of blocks, I think we need to take a look on a "real" 
usage of a block, to get the design as usable as possible.

I have given some examples of how a user could use some adapted form of 
MI to build applications based on a number of blocks, so I'm interested 
in your view about how to build blocks based applications.

Is the question clearer now?


View raw message