如果一个父类(A)和它的子类(A1)都是抽象的(有需要继承他们的子类实现的方法或者设置的属性). 这时应该如何设计接口使得使用子类(A1)的人知道: 不仅需要实现子类中的方法, 还要实现父类中的方法? - V2EX
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 5277 次点击
    这是一个创建于 4360 天前的主题,其中的信息可能已经有所发展或是发生改变。
    --- 两个父子关系的抽象类

    比如, 我有一个 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  
    &bsp;  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     Solana     1291 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 17:09 PVG 01:09 LAX 09:09 JFK 12:09
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86