面向对象思想理论
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的实现类进行调用

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

相关内容

热门资讯

中国银行招标结果:中国银行北京... 证券之星消息,根据天眼查APP-财产线索数据整理,中国银行股份有限公司5月24日发布《中国银行北京庄...
原创 A... "上下同欲者胜。"——《孙子兵法》 “厂家那边又逼我压两百万的货,可库存早都冒了。” 凌晨两点...
原创 “... 全款买房”和贷款30年,差别到底有多大?曹德旺一句话点醒了很多人 前阵子,一个朋友把看了半年的房子终...
云英谷科技登陆港交所:AI终端... 5月27日,云英谷科技股份有限公司(股票简称:云英谷科技,股票代码:3310.HK)成功登陆港交所主...
京东集团与三一集团签订战略合作... 5月25日,京东集团与三一集团在北京签署战略合作协议。京东集团SEC副主席、京东集团CEO许冉与三一...
青岛的朋友看过来:黄金回收我跑... 前阵子想把家里一些旧金饰处理掉,在青岛问了几家回收黄金的地方。今天就跟大家随便聊聊我打听、上门、对比...
武汉有闲置贵重金属变现需求该怎... 不少有黄金回收需求的用户不知道该如何挑选合适的服务机构,其实只要从资质、专业度、服务能力、口碑几个维...
业绩再度下滑,石药集团一季度归... 图片来源:视觉中国 蓝鲸新闻5月27日讯(记者 屠俊)5月27日午间,石药集团(01093.HK)公...
蚂蚁CEO韩歆毅:在Agent... 【CNMO科技消息】近日,蚂蚁集团CEO韩歆毅在演讲中,系统分享了关于智能体经济和AI支付的底层思考...
Buff叠满!芯片,双重利好!... 芯片领域,传来两则大消息! 一是5月27日有媒体报道称,台积电3纳米制程下半年将涨价15%,明年或再...
“全球正面临第五次油价冲击” 日本央行行长植田和男27日在东京说,自上世纪70年代以来,全球多次经历能源价格急剧上涨,当前全球正面...
白酒股,直线拉升!600779... 【导读】白酒股终于涨了 中国基金报记者 泰勒 大家好,花有重开日,人无再少年。就在刚刚,低迷许久的“...
河北地区闲置名酒如何合规变现 闲置名酒处置的行业现状 近年来随着居民酒类收藏意识的逐步提升,不少家庭都存有不同品类的年份名酒,当...
重磅!长鑫科技科创板IPO获通... 5月27日消息,长鑫科技科创板IPO获上交所上市委会议通过。
东方基金开展“一司一省一高校”... 为深入贯彻落实新“国九条”以及《推动公募基金高质量发展行动方案》的核心要求,积极响应证监会对于金融机...
那句「都是卖猪食的」,为什么你... 你大概也笑了一下。 最近有句话在网上传疯了,说字节的副总裁回怼腾讯的“短视频像猪食”,撂了一句“都是...
2026 年小红书多账号管理工... 摘要 2026 年小红书矩阵运营成品牌获客主流,但账号风控严、消息分散、转化低效等痛点突出。本文基...
打着高知女性旗号割韭菜,“五个... 出品丨搜狐财经 作者丨柴鑫洋 编辑丨李文贤 你被“五个女博士”种草过吗? 打着高知女性旗号,却做着低...
A股董责险渗透率破32%,海南... 开栏语: 保险是经济的“减震器”,但保险条款复杂晦涩,犹如海下暗礁。 即日起,海财经·证券导报开设“...
奥尼电子:49万股限制性股票将... 5月27日,奥尼电子(301189)发布公告,2025年限制性股票激励计划第一个归属期归属结果已确定...