面向对象思想理论
admin
2024-03-13 13:33:10
0

文章目录

  • 面向对象的四大特性
  • 面向对象和面向过程的比较
  • 接口和抽象类
    • 定义比较
    • 出发点
    • 抽象类设计思路
  • 模拟抽象类和借口
    • 接口模拟
    • 模拟抽象类
  • 基于接口而非实现编程
  • 多用组合少用继承
    • 为什么不推荐使用继承
    • 组合相比继承有哪些优势?

面向对象的四大特性

  • 封装性:信息隐藏或者数据访问保护,类通过暴露有限的访问接口,授权外部仅能通过类提供的方式(或者叫函数)来访问内部信息或者数据
  • 抽象性:如何隐藏方法的具体实现,让调用者只需要关心方法提供了哪些功能,并不需要知道这些功能是如何实现的
  • 继承:表示类之间is-a关系,代码复用
  • 多态:子类可以替换父类,在实际的代码运行过程中,调用子类的方法实现

面向对象和面向过程的比较

  • 什么是面向过程编程与面向过程编程语言?
    1. 面向对象编程是以类为基本单元,而面向过程编程则是以过程(或方法)作为组织代码的基本单元,最重要的特点是数据和方法分离。
    2. 不支持丰富的面向对象编程特性,如继承,多态,封装。
  • 面向对象编程相比面向过程编程有哪些优势?
    1. 对于大规模复杂程序的开发,程序的处理流程并非单一的是一条主线,而是错综复杂的网状结构。面向对象编程比起面向过程编程,更能应对这种复杂类型的程序开发
    2. 面向对象编程相比面向过程编程,具有更加丰富的特性(封装、抽象、继承、多态)。利用这些特性编写出来的代码,更加易扩展、易复用、易维护。
  • 为什么说面向对象编程语言比面向过程编程语言更高级?
    1. 更接近人的思维逻辑,将事务抽象为类,再去逐步完善行为。而面向过程则更加接近底层,需要我们有计算机思维。
  • 有哪些看似是面向对象实际上是面向过程风格的代码?
    1. 滥用get,set
    2. 滥用全局变量和全局方法。只包含静态方法而不包含任何属性的utils类,是彻彻底底的面向过程的编程风格。
    3. 定义数据和方法分离的类,如mvc编程(贫血模型)
  • 在面向对象编程中,为什么容易写出面向过程风格的代码?
    1. 思维模式的不同,面向过程是一步步按照顺序来,面向对象是一种自底而上的思考方式,不是按照执行流程去分解任务,而是将任务翻译成一个个小的模块,模块之间进行交互
  • 面向过程编程和面向过程语言就真的没有用武之地了吗?
    1. 看使用场景,如计算为主,数据为辅的情况下,就可以使用面向过程

接口和抽象类

定义比较

抽象类:(is-a)

  1. 抽象类不允许被实例化,只能被继承
  2. 抽象类可以包含属性和方法,且可以包含代码实现,也可以不包含代码实现,不包含代码实现的方法叫做抽象方法
  3. 子类继承抽象类,必须实现抽象类中的所有抽象方法。

接口类:(has-a)

  1. 接口不能包含属性(也就是成员变量)
  2. 接口只能声明方法,方法不能包含代码实现
  3. 类实现接口的时候,必须实现接口中声明的所有方法

出发点

抽象类是多个子类代码重复,对整体重复代码抽离出来,是自下而上的。
接口偏重于解耦,是对行为的抽象,相对于一组协议或者契约,构建接口经常是自上而下的。

抽象类设计思路

public class Logger {private String name;private boolean enabled;private Level minPermittedLevel;public Logger(String name, boolean enabled, Level minPermittedLevel) {this.name = name;this.enabled = enabled;this.minPermittedLevel = minPermittedLevel;}protected boolean isLoggable(Level level) {boolean loggable = enabled & (minPermittedLevel.intValue <= level.intValue);return loggable;}
}// 文件子类class FileLogger extends Logger {private Writer writer;private String filePath;public FileLogger(String name, boolean enabled, Level minPermittedLevel, String filePath) {super(name, enabled, minPermittedLevel);this.filePath = filePath;}public void log(Level level, String message) {if (!isLoggable(level)); return;writer.write(message);}
}// 中间间输出子类
class MessageQueueLogger extends Logger {private MessageQuesueClient messageQuesueClient;public MessageQueueLogger(String name, boolean enabled, Level minPermittedLevel, MessageQuesueClient messageQuesueClient) {super(name, enabled, minPermittedLevel);this.messageQuesueClient = messageQuesueClient;}public void log(Level level, String message) {if (!isLoggable(level)); return;messageQuesueClient.send(message);}
}

固然说这样子达到了代码复用的目的,但是已经无法使用多态特性了,不能用logger去调用log方法
还有一种,就是写一个空log(),但是相对于抽象类而言,还是脱了裤子放屁,而且定义一个空方法,其他人也不容易去理解,也有可能忘记了该方法的实现

模拟抽象类和借口

接口模拟

接口就是没有定义成员变量,只有方法声明,没有方法实现

  1. 使用抽象类模拟
class Strategy {public:~Strategy();virtual void algorithm()=0;protected:Strategy(); 
}

没有定义任何属性,且所有方法都声明为virtual类型,这样所有方法都没有代码实现,且继承这个抽象类的子类都必须实现这些方法,从语法特性来说,相当于一个接口。

  1. 用普通类模拟接口
public calss MockInterface {protected MockInterface() {}public void funcA() {throws new MethodUnSupportedException();}
}

该类构造方法是protected,只可以继承。且不重写funA,会抛出MethodUnSupportedException异常,这样就强迫子类在继承这个夫类时,都要主动实现夫类的方法。

模拟抽象类

抽象类的概念是有属性,有方法,可以有方法没有实现

用普通类实现抽象类

public calss MockInterface {private int value;protected MockInterface() {}public void funcA() {throws new MethodUnSupportedException();}
}

和模拟接口类似,将构造方法保护起来,只能通过继承来实现,且未实现方法需要定义抛出异常

基于接口而非实现编程

广泛的对于接口的定义: 一组协议或者约定,是功能提供者提供给使用者的一个功能列表

越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性,越能应对未来的需求变化。好的代码设计,不仅能应对当下的需求,而且在将来需求发生变化的时候,仍然能够在不破坏原有代码设计的情况下灵活应对。

以图片上传为例
现在有一个向阿里云上传图片的类,如下

public class AliyunImageStore {// ... 省略属性、构造方法....public void createBucketIfNotExisting(String bucketName) {// 创建bucket代码逻辑。。。// 。。。失败抛出异常}public String generateAccessToken() {// 根据 accesskey / secretkey 等生成access token}public String uploadToAliyun(Image image, String bucketName, String accessToken) {// 上传图片到阿里云// 返回图片储存地址}public Image downloadFromAliyun(String url, String accessToken) {// 从阿里云下载图片返回}
}// AliyunImageStore类使用实例
public class ImageProcessingJob {private static final String BUCKET_NAME = "al_image_bucket";// .....public void process() {Image image = ...; // 处理图片,并封装为Image对象AliyunImageStore imageStore = new AliyunImageStore();imageStore.createBucketIfNotExisting(BUCKET_NAME);String accessToken = imageStore.generateAccessToken();imageStore.uploadToAliyun(image, BUCKET_NAME, accessToken);}}

上述流程分为了三个步骤:创建bucket(存储目录),生成accessToken,携带token上传图片到指定的buckey中。整个流程看起来没有什么问题。

现在不往阿里云上放东西了,改成私有云了,那这个类就需要进行大改,如生成token,类名,方法名等。而且我们对这个行为进行抽象,他们都具有上传和下载功能,姑可以将该方法抽象出来。

public interface ImageStore {String uploadImage(Image image, String bucketName);Image download(String url);
}// 阿里云存储
public class AliyunImageStore implements ImageStore{// ... 省略属性、构造方法....public void createBucketIfNotExisting(String bucketName) {// 创建bucket代码逻辑。。。// 。。。失败抛出异常}public String generateAccessToken() {// 根据 accesskey / secretkey 等生成access token}@Overridepublic String uploadImage(Image image, String bucketName) {createBucketIfNotExisting(bucketName);String token = generateAccessToken();// 上传图片到阿里云// 返回图片储存地址}@Overridepublic Image download(String url) {String token = generateAccessToken();// 从阿里云下载图片返回}
}// 本地云存储
public class PrivateImageStore implements ImageStore{public void createBucketIfNotExisting(String bucketName) {// 创建bucket代码逻辑。。。// 。。。失败抛出异常}@Overridepublic String uploadImage(Image image, String bucketName) {createBucketIfNotExisting(bucketName);// 上传图片到私有云// 返回地址}@Overridepublic Image download(String url) {// 从私有云下载图片。。。}
}// 调用
public class ImageProcessingJob {private static final String BUCKET_NAME = "al_image_bucket";// .....public void process() {Image image = ...; // 处理图片,并封装为Image对象ImageStore imageStore = new AliyunImageStore();imageStore.uploadImage(image, BUCKET_NAME);}}

注意:

  1. 最好不要将类写完后反推接口,这可能导致接口定义不够抽象,依赖具体的实现
  2. 只有当系统存在不稳定的实现时,需要将其抽象出来,当系统问题,不需要每一个类都去定义接口。
  3. 定义接口时,一方面,命名要足够通用,不能包换跟具体实现相关的字眼;另一方面,于特定实现有关的方法不要定义在接口中

上述的使用也是存在问题的

ImageStore imageStore = new AliyunImageStore(); //更换图片存储方法不方便

解决思路:

  • 配置文件
  • 构造方法传参
  • 工厂模式,ImageStore imageStore = ImageStoreFactory.newInstance(STORE_TYPE_CONFIG);
  • 依赖注入
  • 策略模式,使用一个Context类,使用聚合持有这个接口实例饮用,其他地方都用这个context类,变动只改动这个context类

多用组合少用继承

为什么不推荐使用继承

继承解决了代码复用问题,但是如果继承层次过深,过复杂,也会影响到代码的可维护性。

例如要设计一个鸟类这样的一个抽象的事物概念,定义为一个抽象类AbstractBird。
现在有需求:鸟会飞,会跑,会下蛋,我们是否要定义这些方法
那不会飞,不会跑,不会下蛋的鸟也很多,那该怎么办呢?
就拿飞举例,给不会飞的鸟抛出异常,这固然是一种方法,还有就是再通过AbstractBird派生出两个更加细分的类,会飞的鸟和不会飞的鸟,哪再加上会跑,2*2就是要定义4个了,再有具体的要求,结构就越来越复杂,而且更改父类逻辑,子类也会收到影响。

组合相比继承有哪些优势?

常用的三种方式:组合,接口,委托,一块解决继承的问题。
对于会飞的特性,定义一个flyable(),去实现这个接口,将实现类放入鸟类的成员变量中去,如果要调用fly的方法,就可以通flyable的实现类进行调用

尽管我们鼓励多用组合少用继承,但组合也并不是完美的,继承也并非一无是处。在实际的项目开发中,我们还是要根据具体的情况,来选择该用继承还是组合。如果类之间的继承结构稳定,层次比较浅,关系不复杂,我们就可以大胆地使用继承。反之,我们就尽量使用组合来替代继承。除此之外,还有一些设计模式、特殊的应用场景,会固定使用继承或者组合。

相关内容

热门资讯

原创 深... 你要说这两年深圳的“港味儿”有多浓?去趟山姆超市或者COCO Park溜达一圈就知道了。别说普通话,...
原创 下... 黄金市场正处在一个前所未有的紧绷时刻。 2026年2月26日,伦敦现货黄金价格在一天之内上演了深V反...
上海安路信息科技股份有限公司2... 本公司董事会及全体董事保证本公告内容不存在任何虚假记载、误导性陈述或者重大遗漏,并对其内容的真实性、...
日本试采深海稀土泥,成本是中国... 来源:市场资讯 (来源:时报新征途) 央视网近日报道,日本是全球第二大稀土消费国,仅次于中国。但日...
原创 雷... 本来以为2月28日晚上,小米在巴塞罗那的发布会就是走个过场,把小米17系列在海外发一发,结果雷总根本...
人民币汇率破6.87,按现价算... 这段时间人民币兑美元汇率一直在不断上升。 截至目前,人民币在岸和离岸对美元汇率纷纷都破了6.87,其...
原创 扛... 特朗普向中国服软,中方禁令引起连锁反应。 2月26日,中国就将继续推进对中国履行中美第一阶段经贸协议...
原创 发... 先看一个老生常谈的现象:春节酒店价格又涨了。 今年春节出游的情绪明显回升,外出“旅游式过年”与返乡“...
经纪业务管理薄弱、营销宣传不规... (图片来源:视觉中国) 蓝鲸新闻2月28日讯(记者 王婉莹)中山证券合规问题再添“新伤”。日前,深圳...
以色列突袭伊朗!炸弹落在德黑兰... 来源:市场资讯 (来源:预见能源) 德黑兰市中心的爆炸声,让全球石油市场的神经瞬间绷到最紧。 2月...
金饰克价,冲上1600元!最新... 据央视新闻消息,当地时间28日,伊朗首都德黑兰发生爆炸。以色列国防部长表示,以色列对伊朗发动了先发制...
做到全球第一却累亏28亿,大疆... 出品 | 创业最前线 作者 | 星空 编辑 | 蛋总 美编 | 倩倩 审核 | 颂文 在全球人口老龄...
卷入“关联交易”风波,陆金所换... 作者 |付影 来源 | 独角金融 正处于“多事之春”的陆金所控股(6623.HK;LU.US),再现...
珠海华润银行更名为广东华润银行... 珠海华润银行完成更名。 2月28日,珠海华润银行(下称华润银行)发布公告称,根据该行董事会、股东大会...
五粮液一把手被查,离退休仅两年 来源:21世纪经济报道 记者丨肖夏 编辑丨高梦阳 朱益民 刘雪莹 央视新闻2月28日晚间披露,四川省...
佛山综保区有了“国际驿站” 2月28日,佛山综合保税区管理局与佛山市贸促会(佛山国际商会)展开交流并进行签约,由佛山市贸促会(佛...
微软与OpenAI重申合作:相... 来源:环球网 【环球网科技综合报道】2月28日消息,据多家外媒报道,融资消息曝出后,微软与Open...
供给趋紧需求爆发 小金属上演“... 本报记者 李立平 近日,素有“工业维生素”之称的小金属板块,成为资金追捧的焦点。2月27日,小金属板...
险资开年调研1319次,覆盖4... 图源:图虫创意 2026年以来,保险资金调研热情持续高涨,成为A股市场的重要风向标。 时代周报记者据...
原创 丑... 特朗普访华前夕,中国警告美国不要挑事。美国当地时间2月24日,美国贸易代表格里尔在接受媒体采访时,公...