Problem with Decorator pattern, iOS / UICollectionViewCells

I am trying to "decorate" UICollectionViewCells using the Decorator template.

For example, if I have

BaseCell : UICollectionViewCell 

I would like to do something like this:

  BaseCell *cell = [[BaseCell alloc] initWithFrame] cell = [[GlowingCell alloc] initWithCell:cell]; cell = [[BorderedCell alloc] initWithCell:cell]; cell = [[LabelledCell alloc] initWithCell:cell]; // cell is now a glowing, bordered, labelled cell. 

I think the Decorator pattern is pretty neat for this kind of thing, but it's hard for me to apply it to collectibles.

First, in UICollectionViewControllers you need to register a class, for example:

  [self.collectionView registerClass:cellClass forCellWithReuseIdentifier:cellIdentifier]; 

Therefore, I have no way to create my own instance.

Secondly, I do not see how Decorator can ever be useful for decorating "unclean" objects, that is, objects that I did not create from scratch, but have their own properties and behavior (for example, UICollectionViewCell). Since in the above example, cell represents a new instance of LabelledCell, and if the UICollectionView makes a method call, for example isSelected , it will call aLabelledCellInstance.isSelected , unless I specifically do this in the Decorator base class:

  - (BOOL)isSelected { return self.decoratedCell.isSelected; } 

This is good for a single method, but does not seem to have the right to override each method in a UICollectionViewCell . Should I use forwardInvocation: :?

I am abusing this template, and are there any alternatives? Because it works very well in books when you just need to override basic methods, for example

  getPrice() { return decoratedObject.getPrice() + 1.10f; } 

.. but it seems difficult to actually fit into existing UI elements with user behavior.

thanks

EDIT: I try to avoid such classes:

  • GlowingBorderedCell
  • LabelledGlowingBorderedCell
  • and etc.

On paper, Decorator is the perfect candidate for what I'm trying to achieve, but the implementation completely surpassed me.

+8
design-patterns ios decorator iphone uicollectionview
source share
2 answers

First, the Decorator pattern requires that you redefine all the base methods in BaseDecorator to forward calls to the decorated object. And you can do this either by overriding each method, or preferably just use forwardInvocation: And since all other decorators will be subclasses of BaseDecorator , now you can simply override the methods you want to change.

Secondly, for the CollectionView problem, I suggest using the Decorator template with the usual UIView s, and then use the decorated view as the contentView cell. Consider an example:

We have a BaseCellView class that will be a BaseCellView for all decorators.

 BaseCellView : UIView; GlowingCellView: BaseCellView; BorderedCell: BaseCellView; LabelledCell: BaseCellView; 

And we have our BaseCell class, which is a subclass of UICollectionViewCell :

 BaseCell : UICollectionViewCell; 

Now UICollectionViewControllers will always create an instance of BaseCell and give you the opportunity to configure it, where you will do the following:

 BaseCellView *cellView = [[BaseCellView alloc] initWithFrame] cellView = [[GlowingCellView alloc] initWithCellView:cellView]; cellView = [[BorderedCellView alloc] initWithCellView:cellView]; cellView = [[LabelledCellView alloc] initWithCellView:cellView]; cell.contentView = cellView; 

And yet you can forward any UICollectionViewCell decorator if you wish.

+4
source share

Here's a post in which I described this technique. Although I decided to decorate the UITableView , not the cell, it can easily be adapted to your collector's view. This is a pretty long read, so I will just do a short summary here:

  • the decorator must be a proxy object in order to be able to forward all messages to the decorated object.
  • There are several methods that you must override in your decorator to make this happen, including respondsToSelector and forwardingTargetForSelector
  • when you're done, you can hook up the decorators, which are pretty neat:

eg:.

 dec = [[DEFooterDecorator alloc] initWithDecoratedObject:dec]; dec = [[DEHeaderDecorator alloc] initWithDecoratedObject:dec]; dec = [[DEGreenCellDecorator alloc] initWithDecoratedObject:dec]; 
+3
source share

All Articles