装饰模式,iOS / UICollectionViewCells的麻烦

时间:2013-02-01 18:07:14

标签: iphone ios design-patterns decorator uicollectionview

我正在尝试使用Decorator模式'装饰'UICollectionViewCells。

例如,如果我有

 BaseCell : UICollectionViewCell 

我希望能够做到这样的事情:

 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.

我认为Decorator模式对于这类事情来说非常简洁,但是我很难将它应用于集合视图。

首先,在UICollectionViewControllers中,您需要注册一个类,如下所示:

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

所以我没有机会制作自己的实例。

其次,我无法看到装饰器如何用于装饰“非纯”对象,即我没有从头开始创建但具有自己的属性和行为的对象(例如UICollectionViewCell)。由于在上面的示例中,cell表示LabelledCell的新实例,并且如果UICollectionView对方法(例如isSelected)进行调用,则会调用aLabelledCellInstance.isSelected,除非我特别在我的装饰者基类:

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

对于一种方法哪个好,但是必须覆盖UICollectionViewCell中的每个方法似乎都没有。我应该使用forwardInvocation:吗?

我是否滥用这种模式,还有其他选择吗?因为它只需要覆盖基本方法,如

,它在书籍中的效果非常好
 getPrice() {
      return decoratedObject.getPrice() + 1.10f;
 }

..但似乎很难适应实际使用自定义行为装饰现有UI元素的目的。

由于

编辑:我想避免的是这样的课程:

  • GlowingBorderedCell
  • LabelledGlowingBorderedCell

在纸面上,装饰师是我想要实现的目标的完美候选者,但实施绝对让我感到难过。

2 个答案:

答案 0 :(得分:4)

首先,Decorator模式要求您覆盖BaseDecorator中的所有基本方法,以便可以将调用转发给装饰对象。 你可以通过覆盖每一种方法来做到这一点,或者最好只使用forwardInvocation:。由于所有其他装饰器都是BaseDecorator的子类,您现在可以覆盖您想要更改的方法。

其次,对于CollectionView问题,我建议将Decorator模式与普通UIView s一起使用,然后将装饰视图用作单元格的contentView。 我们来看一个例子:

我们有BaseCellView类,它将成为所有装饰者的超类。

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

我们仍然有BaseCell类,它是UICollectionViewCell的子类:

BaseCell : UICollectionViewCell;

现在,UICollectionViewControllers将始终创建BaseCell的实例,并为您提供配置它的机会,您将在其中执行以下操作:

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

如果你愿意的话,你仍然可以将任何UICollectionViewCell转发给装饰者。

答案 1 :(得分:3)

Here这是我描述过这种技巧的帖子。虽然我选择装饰UITableView而不是单元格,但它可以很容易地适应您的集合视图。这是一个很长的阅读,所以我只在这里做一个简短的总结:

  • 装饰器需要是一个代理对象才能将所有消息转发到装饰对象
  • 您需要在装饰器中覆盖多种方法才能实现这一点,其中包括respondsToSelectorforwardingTargetForSelector
  • 完成后,你将能够链接装饰很漂亮:

e.g:

dec = [[DEFooterDecorator alloc] initWithDecoratedObject:dec];
dec = [[DEHeaderDecorator alloc] initWithDecoratedObject:dec];
dec = [[DEGreenCellDecorator alloc] initWithDecoratedObject:dec];