【问题标题】:How to avoid duplicate code objective-c如何避免重复代码objective-c
【发布时间】:2012-06-19 12:16:49
【问题描述】:

我有两种不同的方式在我的应用中表示数据:通过UITableViewUIScrollView
所以我有 2 个主要课程:AppTableView: UITableViewAppScrollView: UIScrollView。 我想对两个视图实现相同的添加。所以我写了两个类:SomeAdditionsTableView: UITableViewSomeAdditionsScrollView: UIScrollView。这个类的代码是一样的。 主类现在看起来像
AppTableView: SomeAdditionsTableViewAppScrollView: SomeAdditionsScrollView

如何避免此代码重复?提前致谢。

【问题讨论】:

  • 这两门课你都有什么?
  • 如果对您有帮助,您可以只制作一个 SomeAdditionsScrollView:UIScrollView 并删除 SomeAdditionsTableView: UITableView,因为 UITableView 是 UIScrollView。然后你可以使用 SomeAdditionsScrollView 作为 AppTableView 和 AppScrollView 的超类
  • @AdrianAncuta 我不相信这会奏效。如果子类化 UIScrollView (SomeAdditionsScrollView:UIScrollView) UITableView 仍将直接继承 UIScrollView 并且不会获得 SomeAdditionsScrollView 的好处。如果 AppTableView 子类 SomeAdditionsScrollView 它将不再是一个 tableView。
  • @Aaron Hayman 你是完全正确的。然后它应该尝试制作 SomeAdditionsScrollView:UITableView。这样一来,两者都将成为他们所需要的。
  • @Adrian Ancuta,感谢您的回答。但是,如果我使用 SomeAdditionsScrollView 作为 AppTableView 的超类,我将无法在 AppTableView 中使用 UITableView 属性和方法(separatorStyle、separatorColor 等)。

标签: objective-c ios oop


【解决方案1】:

是的,这是 Objective-c 中缺少多重继承的问题。当我在这里分别需要 UIView 和 UIScrollView 的子类上的某些方法时,我遇到了同样的问题:Subclassing UIView vs UIScrollView。我知道有 3 种可能的解决方案:

  1. 如果您不需要存储任何类型的实例变量,只需在 UIScrollView 上声明一个类别并确保将该类别导入到两个子类中。这是最简单的解决方案,但最不可能奏效,因为如果要进行子类化,您可能需要存储状态信息。
  2. 只创建一个 UITableView 的子类,并且当你不想要 UITableView 时,根本不要将它用作 UITableView。从技术上讲,您可以将 UITableView 用作 UIScrollView 而无需调用任何 tableView 的方法。当然,您最终会承担 tableView 的“权重”(所有这些都是实例变量),但没有理由必须将 UITableView 用作 UITableView 而不仅仅是 UIScrollView。
  3. 将尽可能多的代码委托给一个单独的对象,以最大限度地减少代码重复。在每个单独的子类中携带一个实例变量,该变量是方法委托和将方法调用转发到该委托。现在这里很有趣。您可以使用协议在子类中声明委托方法并覆盖特殊的 NSObject 方法:- (id) forwardingTargetForSelector:(SEL)aSelector 以确保将这些方法调用发送到委托。您在子类上使用符合委托类中声明的协议的类别。这将在子类中公开委托类的所有方法,而无需您在子类中实际实现这些方法。当运行时在子类中找不到声明的方法时,它将调用- (id) forwardingTargetForSelector:(SEL)aSelector,您可以使用它来返回您的委托/转发类。这将防止您需要转发每个单独的方法。根据这些方法调用的作用,这可能需要更多的“接线”,但最终会为您节省大量代码编写。它本质上是使用协议“模仿”objective-c 中的多重继承。有关详细信息,请在此处查看我的问题/答案:https://stackoverflow.com/a/9419587/1147934

在这三个中,最后一个选项对我来说效果最好。需要做一些工作才能理解,但会显着减少代码重复。当我想在没有子类的情况下进行子类化时,我也会使用它。然而,最大的要求是,任何你想要使用的类都必须将它的方法声明从它的接口移到一个单独的协议中。但这真的没什么大不了的,获得“类似行为的多重继承”的好处是巨大的。

此外,有时您可能需要转发类来访问转发类(子类)中的实例变量。您可以通过使用委托模式来实现这一点,其中转发类维护对转发类的弱引用以访问这些实例变量。例如,在您的情况下,如果您尝试委托对 UIScrollView 进行操作的方法,则这些方法可能需要能够访问该视图。如果这些方法被困在委托类中,除非您将其提供给它们,否则它们将无法直接访问视图的变量。与任何委托模式一样,请务必小心不要创建保留循环。

【讨论】:

  • 我认为方法 3 是一种用于单继承语言的混合实现;我以前在 PHP 中使用过它;在 MI 语言中,mixin 非常强大,可以消除大量代码重复。我实际上认为 mixins 可以用来实现面向方面的编程。无论如何...我喜欢你的方法。
【解决方案2】:

如果您的添加不需要任何自己的状态,您可以在UIScrollView 上将它们设为category。然后,由于 UITableViewUIScrollView 的一种类型,您也可以在其中一个上使用类别方法。

如果他们确实需要定义新变量,那么我会将其设为一个独立的类,并拥有一个带有 SomeAdditions 属性的 MyTableView : UITableView 子类,以及类似的 MyScrollView : UIScrollView

【讨论】:

    【解决方案3】:

    您可以通过使用协议和“has_a”-relationships 而不是继承的“is_a”-relationships 实现很多目标。
    一种非常常见的模式是委托,但协议也可用于将方法调用转发到封装或包装的对象。
    在下面的示例中,彼此不相关的类共享一个公共对象,但同样的对象也有可能使用不同类的对象,它们都实现了一个公共协议,所以相等的对象可以做非常不同的东西。

    @interface ClassA : NSObject
    @property (strong) id<BrainProtocol> *brain
    @end
    
    @@implementation ClassA
    @synthezise brain;
    
    -(void)theMethod
    {
        [brain theMethod];
    }
    @end
    

    @interface ClassB : NSObject
    @property (strong) id<BrainProtocol> *brain
    @end
    
    @@implementation ClassB
    @synthezise brain;
    
    -(void)theMethod
    {
        [brain theMethod];
    }
    @end
    

    ClassA *a = [[ClassA alloc] init];
    ClassB *b = [[ClassB alloc] init];
    
    //A object, that implements the BrainProtocol
    
    Brain *brain = [[brain alloc] init];
    [a setBrain:brain];
    [b setBrain:brain]; 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-29
      • 1970-01-01
      • 1970-01-01
      • 2018-08-16
      • 2014-03-07
      相关资源
      最近更新 更多