V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
thedevil5032
V2EX  ›  iDev

如果一个父类(A)和它的子类(A1)都是抽象的(有需要继承他们的子类实现的方法或者设置的属性). 这时应该如何设计接口使得使用子类(A1)的人知道: 不仅需要实现子类中的方法, 还要实现父类中的方法?

  •  
  •   thedevil5032 · 2014-01-10 10:30:16 +08:00 · 4845 次点击
    这是一个创建于 3998 天前的主题,其中的信息可能已经有所发展或是发生改变。
    --- 两个父子关系的抽象类

    比如, 我有一个 XXXViewController 以及一个 EditableXXXViewController. 显然 XXXViewController 为 EditableXXXViewController 的父类. XXXViewController 只能显示数据, 但是 EditableXXXViewController 在其父类的基础上除了显示, 还可以编辑数据, 例如添加, 删除等.

    当继承 XXXViewController 时, 必须实现的方法有 configureXXX.
    而 EditableXXXViewController 必须实现的方法有 configureNewXXX, 以及其父类的 configureXXX.

    --- 我想到的解决办法(A, B 为不同方法)

    A. 每个类需要其子类实现的 **所有** 方法以及属性放入一个 Protocol, 类本身遵循这个 Protocol, 并且提供这些方法的空实现.
    B. 将这些需要实现的方法和属性放入一个 Delegate 中, 同上, Delegate 用一个 Protocol 阐明 **所有** 方法和属性.

    * 所有: 也就是说, 子类的 Protocol 实际上并不继承父类的 Protocol, 但 Protocol 包含父类需要实现的方法. (或许这不是一个好的解决方案)

    --- TL;DR

    困扰我的就是如何能让用 EditableXXXViewController 的人不用走弯路就知道需要实现它的父类方法?

    ----
    初学 Objective-C, 还不是太了解 Objective-C 的设计方法. 所以这个问题或许不是接口设计的问题, 也可能是本身两个类设计的问题.

    各位有任何建议都可以提出来, 谢谢. 回复必谢. :D
    11 条回复    1970-01-01 08:00:00 +08:00
    dnnta
        1
    dnnta  
       2014-01-10 11:53:29 +08:00   ❤️ 1
    可以这样试一下
    父类中
    - configureXXX {
    [NSException raise:NSInternalInconsistencyException
    format:@“在%@子类中必须重载%@方法”, [NSString stringWithUTF8String:object_getClassName(self)], NSStringFromSelector(_cmd)];
    }
    如果子类调用时没有重写父类configureXXX 肯定会抛异常了
    fangzhzh
        2
    fangzhzh  
       2014-01-10 11:58:39 +08:00   ❤️ 1
    我感觉 XXXViewController,EditableXXXViewController 这个类关系可以定义为
    类XXXViewController, 和接口 editable, 然后XXXViewController 实现接口. 子类继承XXXViewController时, 可能就必须要关心editable的接口了.
    PrideChung
        3
    PrideChung  
       2014-01-10 12:32:16 +08:00   ❤️ 1
    @fangzhzh 既然你两个类都是抽象的,本身一个方法都不实现,还不如弄成两个protocol,XXXing,XXXEditing,然后让UIViewController的子类去实现它们。
    railgun
        4
    railgun  
       2014-01-10 12:32:53 +08:00   ❤️ 1
    我的理解,楼主所说的抽象类在ObjC里面的实现就是协议
    两个协议,协议方法都是@request ,继承关系,应该能满足楼主的需求
    fangzhzh
        5
    fangzhzh  
       2014-01-10 12:36:51 +08:00   ❤️ 1
    @PrideChung 因为不了解XXXing是什么, 所以没有那么去想.
    如果是个动作的话, 并且和Editable是正交的概念, 那么两个protocol也是是更好的方案.
    thedevil5032
        6
    thedevil5032  
    OP
       2014-01-10 13:28:45 +08:00
    ---- 具体的例子

    比如我有一个 CoreDataTableViewController, 继承这个类的子类设置好一个 NSFetchedResultsController 并且实现 cofigureCell: 方法, 就可以从 CoreData 中装载数据, 并在 TableView 中显示.
    不过 CoreDataTableViewController 只有显示数据的功能, 不能更改其中的数据. 所以就有了EditableCoreDataTableViewController, 它就具有添加, 删除的功能. 只要继承 EditableCoreDataTableViewController 的子类实现了 configureNewItem: 就可以向其中添加新的数据. 当然它也需要实现 CoreDataTableViewController 需要的 cofigureCell: 方法.

    其实现在想想, 为什么要 EditableCoreDataTableViewController 类呢, 我也可以把 editable 这部分的功能放在 CoreDataTableViewController 这个里面...

    ---- 总结一下
    希望对于和我有同样困惑的人有所帮助. 如果哪里说得不对, 还请各位指正. 同时也欢迎继续讨论. :D

    -- 问题
    "如果父类(A)和子类(A1)都有抽象方法, 需要继承他们的子类去实现, 如何设计接口使得继承 A1 的子类不仅仅知道需要实现 A1 的抽象方法, 还需要实现 A 的抽象方法? (子类相对父类就多一个功能的情况下)"
    -- 我现在想到的解决方案
    "由于子类与父类差异并不大, 所以子类的功能可以合并为父类的功能."
    PS. 真是不知道为什么自己一开始要把这个功能分离出来... 害得自己苦苦思考了一天...

    -- 问题扩展
    "如果是在子类和父类差异较大的情况下(例如 UIScrollView 和 UITableView), 可能子类应该提供父类抽象方法的合理默认实现."

    ---- 回复

    @dnnta

    其实我也想过这样去做. 然后我去看了看 UITableViewController 的实现. UITableViewController 自身是遵循 UITableViewDataSource Protocol 的, 而且本身空实现了 UITableViewDataSource 所要求的 tableView:cellForRowAtIndexPath: 方法.

    因为对于继承 UITableViewController 的子类来说, 如果没有实现 tableView:cellForRowAtIndexPath: 这个方法, 是不会报错的(warning/error). 但是如果控制的 TableView 需要这个方法的话, 会在运行时报错(报错大意是说这个方法应该返回一个 cell).

    所以, 按照这样的思路去设计的话, 就和我在帖子正文中提到的 A 方法类似.


    @railgun 您是说的 "@required"?
    @PrideChung

    这两个类都是抽象的意思是指, 他们有一部分方法需要继承他们的子类来实现. 其本身除了这些方法以外, 还有一些方法是他们自身实现的.

    @fangzhzh 这两个类不是正交的概念, 应该是扩展吧.
    railgun
        7
    railgun  
       2014-01-10 13:33:03 +08:00   ❤️ 1
    @thedevil5032 呃,对,是@requested
    fangzhzh
        8
    fangzhzh  
       2014-01-10 13:38:09 +08:00   ❤️ 1
    @thedevil5032 正交很好理解的. 比如一个是runable, 一个shoutable, 这两个概念没有重叠的,就是正交的.

    如果是runable, 一个movable, 概念就可能有重叠,或者包含,就不是正交的.

    其实我也是课本上学来的, 希望没有误导你.

    我有个leader, 概念什么的都不懂, 但是实际工作给他的经验, 总是可以设计出分隔很好的系统.
    repus911
        9
    repus911  
       2014-01-10 17:12:29 +08:00   ❤️ 1
    建议 适配器模式
    这个本来不是继承的问题,你不觉得抽象类继承抽象类很反人类吗?
    alexrezit
        10
    alexrezit  
       2014-01-10 17:20:29 +08:00   ❤️ 1
    @PrideChung
    正解.

    如果一定要用继承的话, 可以判断 self 的 class 是否是某个类的 subclass 然后根据条件判断丢 exception 啊.
    PrideChung
        11
    PrideChung  
       2014-01-10 18:11:18 +08:00   ❤️ 1
    我不太清楚你的业务逻辑,但在objc这种没有抽象类的语言里面搞这么复杂的继承关系无疑是自缚手脚,这年头连Java都在大喊“组合优于继承”了。你可以仔细想想是不是有什么特性可以分到别的类里面实现,然后通过不同的组合来得到不同的特性。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2581 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 11:37 · PVG 19:37 · LAX 03:37 · JFK 06:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.