设计模式之开放-封闭原则(引申出Objective-C中继承、Category、Protocol三者的区别,这点面试常问)

时间:2022-04-23 02:58:21
  1. 开放封闭原则(OCP原则The Open-Closed Principle)是面向对象的核心设计所在。它是说,软件开发实体(类、模块、函数等)应该可以扩展,但是不能修改。

这个原则有两个特征,一个是说“对于扩展是开放的”,另一个是说“对于更改是封闭的”。

我们在编写任何app时,不要寄希望于需求是固定的、不变化的,这是不现实也是不科学的想法,既然需求一定会有变化,那么如何应对这种变化?也就是说。我们所设计的代码可以相对容易的修改,不至于新的需求一来,就将整个程序推倒重写?怎么样的设计才能面对需求的改变却可以保持相对稳定,从而使得app可以在第一个版本后不断推出新的版本呢?开放-封闭原则可以给我们答案。

答案:代码要容易维护又不容易出问题的最好办法是,就是多扩展,少修改。

就比如说,你作为一个公司的老板,规定九点上班,不允许迟到,但是有几个公司骨干,老是迟到,你怎么办?

仔细想想,其实迟到不是主要问题,每天保证8小时工作量,是老板最需要的。甚至说,这个也不是问题,按时完成业绩目标,才是最重要的指标。于是应该改变管理方式,弹性上班,早到早走,晚到晚走等。这其实就是对工作时间或者业绩成绩修改的封闭,对时间制度扩展的开放。

开放-封闭原则的意思是,在设计的时候,要时刻考虑,尽量让这个类足够好,写好了就不要去修改了,如果新的需求来了,我们增加一些类就完事了,原来的代码能不动就不动。绝对对修改关闭是不可能的,无论模块是多么的封闭,多会存在一些无法对之封闭的变化。既然不可能完全封闭,设计人员必须对他设计的模块应该对哪种变化进行封装做出选择。他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。

在我们最初编写代码时,先假设变化不会发生,当变化发生时,我们就创建抽象来隔离以后发生的同类变化。保证在面对需求时,对新需求的改变是通过增加新代码进行的,而不是更改现有代码。(要做到这一步,强烈推荐《大话设计模式》这本书,我所有关于设计模式的博客,都是从这本书中学习而来,只是这本书籍代码是C#实现的,而我学习的时候,是带入了个人对OC以及iOS开发的理解)

开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而,对应用程序中每个部分都刻意的进行抽象同样不是好主意,拒绝不成熟的抽象和抽象本身一样重要。

2. Objective-C中继承、Category、Protocol三者的区别

众所周知,OC是单继承,新出的Swift也是单继承。那么在iOS开发中,我们怎么实现类似多继承的关系?

这是一道面试\笔试题,基本应聘时,如果面试官是从事iOS开发的,很有可能会问到这道题。事实上,我们可以利用OC中的Category和Protocol来达到多继承的效果。如果仅仅只是想要回答这个题目,这样说足够了。

可是,有很多面试官是不会满足于这样一个回答的,会追问你,那么Category和Protocol有什么区别呢?即使没有这样的面试题,我想基于自身驱动,这也是必然要了解,学习的。

利用继承、多态可以很好的保持"对扩展开放,对更改封闭"(即上文提到的开放-封闭原则OCP),这也是面向对象语言保持开放-封闭原则最常见的办法。OC中还有另外两种语法来支持OCP:即Category和Protocol。

Protocol只是声明一套接口,并不能提供具体实现,变相的也算是一种抽象基类的实现方式(OC本身语法并不支持抽象基类)。

Category可以为已有的类提供额外的接口和具体的实现。

Protocol只能提供一套公用的接口声明,并不能提供具体实现,它的行为是,我只负责声明,而不管谁去实现,去如何实现。这样的话,我定义一套接口,可以使任意的类都用不同的方式去实现接口中的方法,就是为遵守了protocol的类提供了一些额外访问这个类的一些接口,像delegate和dataSource用protocol实现是最好的。

Category是对一个功能完备的类的一种补充、扩展,就像一个东西基本功能都完成了,可以用category为这个类添加不同的组件,使得这个类能够适应不同情况的需求(但是这些不同需求最核心的需求要一致)。当然,当某个类非常大的时候,使用category可以按照不同的功能将类的实现分在不同的模块中。还有,虽然category可以访问已有类的实例变量,但不能创建新的实例变量,如果要创建新的实例变量,请使用继承。

继承,它基于Protocol和Category之间,既可以像protocol一样只提供纯粹的接口,也可以像Category一样提供接口的完整实现,可以*定义类的实例变量(这一点,Protocol倒是可以声明实例变量,但是也仅仅是声明而已),而且继承还可以对类以后的方法进行改写,所以继承的力量是最强大的。

在iOS开发中,继承是完全可以完成protocol和category的功能的,那么在开发过程中多多使用继承体系可好?

需要注意的是使用继承还有很大的代价问题。使用继承来进行扩展是一种耦合度很高的行为,对父类可以说是完全依赖,如果继承体系太过复杂,会造成难以维护的问题。如果仅仅只是对类进行扩展,并不建议使用继承,毕竟使用protocol和category是很简单、轻松的。除此之外,在开发过程中,我们应该尽量将界面、功能相似的类的代码提取到基类里面,然后各个子类继承自这个基类,实现各自的其他特殊部分。这样可以大大的优化代码,如果需要修改的话,只需要这倒对应子类修改即可。

category是可以被继承的。在某个父类中定义了category,那么他所有的子类都具有该category;
在需要为某个类创建私有成员方法时,也用category的方式来实现。
Category不能完全代替子类,有以下几个最大的缺点:

    1. 当在Category中覆盖一个继承的方法,在Category中的方法可以通过向super类发送一个消息来调用被继承的方法。但是,如果Category中覆盖的那个方法已经在这个类的其它Category定义过了,则之前定义的方法将没有机会被程序调用
    2. 在Category中无法确定其能够可靠的覆盖某个方法,而这个方法已经在其它的Category中定义过。这个问题在使用Cocoa框架时尤其 突出。当你想覆盖某个框架已经定义好的方法时,该方法已经在其它Category中实现,这样就无法确定哪个定义和实现会被最先使用,带来很大的不确定性。

此博客参考博客链接:http://bbs.itheima.com/thread-117162-1-1.html

设计模式之开放-封闭原则(引申出Objective-C中继承、Category、Protocol三者的区别,这点面试常问)的更多相关文章

  1. 北风设计模式课程---开放封闭原则(Open Closed Principle)

    北风设计模式课程---开放封闭原则(Open Closed Principle) 一.总结 一句话总结: 抽象是开放封闭原则的关键. 1."所有的成员变量都应该设置为私有(Private)& ...

  2. (转) 面向对象设计原则(二):开放-封闭原则(OCP)

    原文:https://blog.csdn.net/tjiyu/article/details/57079927 面向对象设计原则(二):开放-封闭原则(OCP) 开放-封闭原则(Open-closed ...

  3. C++ 设计模式 开放封闭原则 简单示例

    C++ 设计模式 开放封闭原则 简单示例 开放封闭原则(Open Closed Principle)描述 符合开放封闭原则的模块都有两个主要特性: 1. 它们 "面向扩展开放(Open Fo ...

  4. [Python设计模式] 第3~5章 单一职责原则/开放-封闭原则/依赖倒转原则

    github地址:https://github.com/cheesezh/python_design_patterns 单一职责原则 就一个类而言,应该仅有一个引起它变化的原因. 如果一个类承担的职责 ...

  5. 《大话设计模式》num03-04-05---单一职责原则、开放封闭原则、依赖倒转原则

    2018年03月03日 21:19:19 独行侠的守望 阅读数个人分类: 设计模式 版权声明:本文为博主原创文章,转载请注明文章链接. https://blog.csdn.net/xiaoanzi12 ...

  6. 设计模式六大原则——开放封闭原则(OCP)

    什么是开闭原则? 定义:是说软件实体(类.模块.函数等等)应该可以扩展,但是不可修改. 开闭原则主要体现在两个方面: 1.对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况. ...

  7. 开放封闭原则(OCP)

    开放封闭原则 转:http://baike.baidu.com/view/2493421.htm转:http://dev.csdn.net/article/38/38826.shtm 开放封闭原则(O ...

  8. Observer观察者模式与OCP开放-封闭原则

    目录 场景引入 在联网坦克项目中使用观察者模式 总结 在学习Observer观察者模式时发现它符合敏捷开发中的OCP开放-封闭原则, 本文通过一个场景从差的设计开始, 逐步向Observer模式迈进, ...

  9. 面向对象设计原则 开放封闭原则(Open Closed Principle)

    开放封闭原则(OCP,Open Closed Principle) 开放封闭原则是所有面向对象原则的核心. 软件设计本身所追求的目标就是封装变化.降低耦合,而开放封闭原则正是对这一目标的最直接体现. ...

随机推荐

  1. GnuStep使用

    gcc -o main main1.m -I/GNUstep/System/Library/Headers -fconstant-string-class=NSConstantString -L/GN ...

  2. Unity手撸2048小游戏——自动生成4*4棋盘

    1.新建文件夹,命prefabs,将刚刚做成的Chessman拖入该文件下,做成预制体 2.删除panel下的Chessman 3.在panel下,新建一个空对象,命名为Chessboard,大小设置 ...

  3. CF 295A Greg and Array (两次建树,区间更新,单点查询)

    #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm& ...

  4. librtmp推流使用aac编码音频的html5和flash播放问题

    公司项目中使用rtmp推流,音频编码aac.视频编码H264.windows和android平台都没有发现问题.然而在IOS版本的APP中发现几个问题:1. 推流后flash播放异常2. IOS平台微 ...

  5. Android JNI和NDK关系

    1.什么JNI Java Native Interface(JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互.JNI 是本地编程接口,它使得在 Java 虚拟机(VM) ...

  6. TreeMap源码

    一.TreeMap简介 TreeMap是基于红黑树的java版实现,作者Josh Bloch and Doug Lea(这二人在java发展的早期做了重大贡献,比如集合框架JDK1.2.并发包JDK1 ...

  7. 新版知乎登录之post请求

    前言 在上一篇文章中给大家讲解了requests发送post请求的几种方式,并分析了一些使用陷阱. 疑惑 在文章发表之后,有朋友给我留言说,知乎登录就没有使用提交Form表单(application/ ...

  8. DotNetCore跨平台~聊聊中间件

    回到目录 在进行.net core平台之后,我们如果希望在请求过程中添加一些事件是非常容易的,你可以把这些事件做成一个中间件Middleware,然后这些中间件就会以Http pipeline的管道方 ...

  9. day 7-8 协程

    不能无限的开进程,不能无限的开线程最常用的就是开进程池,开线程池.其中回调函数非常重要回调函数其实可以作为一种编程思想,谁好了谁就去调 只要你用并发,就会有锁的问题,但是你不能一直去自己加锁吧那么我们 ...

  10. prototype、proto和constructor的三角关系

    转载整理自http://www.cnblogs.com/xiaohuochai/p/5721552.html#3760057 http://blog.csdn.net/jasonzds/article ...