【问题标题】:Trouble with Decorator pattern, iOS / UICollectionViewCells装饰器模式的问题,iOS / UICollectionViewCells
【发布时间】:2013-01-17 03:01:18
【问题描述】:

我正在尝试使用装饰器模式“装饰” 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.

我认为装饰器模式非常适合这类事情,但我很难将它应用到集合视图中。

首先,在 UICollectionViewControllers 中你需要注册一个类,像这样:

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

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

其次,我看不出装饰器如何能够用于装饰“非纯”对象,即我没有从头开始创建但具有自己的属性和行为的对象(例如UICollectionViewCell)。因为在上面的例子中,cell 代表 LabelledCell 的一个新实例,如果 UICollectionView 调用了一个方法,例如,isSelected,这将调用aLabelledCellInstance.isSelected,除非我在我的 Decorator 基类中专门这样做:

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

这对于一种方法来说很好,但必须覆盖UICollectionViewCell 中的每个方法似乎并不正确。我应该使用forwardInvocation: 吗?

我是否在滥用这种模式,还有其他选择吗?因为当您只需要覆盖诸如

之类的基本方法时,它在书籍中的效果非常好
 getPrice() {
      return decoratedObject.getPrice() + 1.10f;
 }

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

谢谢

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

  • 发光的BorderedCell
  • LabeledGlowingBorderedCell

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

【问题讨论】:

  • 这是一个有趣的问题,我喜欢将其应用于 UI 项目的想法。从实现的角度来看,您质疑是否滥用该模式,实际上取决于可读性和可维护性。如果使用这种模式(即使重写了很多方法)使您的代码更具可读性和可维护性,那就去做吧。如果它掩盖了代码的意图和功能,并且让下一个人更难改变,那么不要
  • 这是它的主要用途之一。
  • @Rob,我了解设计模式的目的,但在 Sam 的情况下,他必须做额外的、可能不太可维护的工作才能使解决方案正常工作。我试图给 Sam 一个基本的判断电话的基础
  • 我不是在批评,我只是在说明 Decorator 最常用于他所询问的 ui 内容。
  • 不得不委派所有方法看起来确实很麻烦,尽管您可以执行编译指示和一些代码折叠。这就是装饰器的工作原理。我想过这样的想法,我认为它们很好。所以你不能注册自己的课程?那个怎么样?这不是他们要求一个类实例化的全部意义吗?

标签: iphone ios design-patterns decorator uicollectionview


【解决方案1】:

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

其次,对于CollectionView问题,我建议使用普通UIViews的Decorator模式,然后使用装饰视图作为单元格的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 转发给装饰者。

【讨论】:

  • 这就是我喜欢 StackOverflow 的原因。很好的答案,我要试试这个。谢谢!
  • 接受这个作为答案,我最终没有使用这种模式,因为我需要在创建后访问各种单元格属性并且不想将它们全部包含在基本装饰器界面中 - 我是现在只是坚持更严格的设计。
  • 我认为您可以将指向Cell 的指针传递给CellView 的初始化程序,这样每个CellView 都可以访问它所装饰的单元格的属性。但你可能会开始觉得它变成了一个骇人听闻的解决方案。
  • 不仅如此,而且在 configureCell 上分配所有装饰器视图而不是重用,是次优的
【解决方案2】:

Here 的帖子中我描述了这种技术。虽然我选择装饰UITableView 而不是单元格,但它可以很容易地适应您的收藏视图。这是一篇很长的文章,所以我在这里只做一个简短的总结:

  • 装饰器必须是代理对象才能将所有消息转发到被装饰对象
  • 您需要在装饰器中重写多种方法来实现这一点,其中respondsToSelectorforwardingTargetForSelector
  • 完成后,您将能够链接装饰器,这非常简洁:

例如:

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

【讨论】:

    猜你喜欢
    • 2016-10-05
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    相关资源
    最近更新 更多