面向对象思想

很多人刚学C++核心编程的时候或者学习Java的时候一定会有一个疑问**

面向对象思想到底是个啥啊?

面向对象到底有啥用啊?

我咋样写代码才是面向对象思想啊?

我们刚接触的C语言是面向过程的思想语言,我们可以很直观的就能看懂每一条代码执行的过程。而面向对象中我们到底该如何去理解和编写?

面向对象到底是个啥

引用了知乎的一篇文章来理解什么是面向对象

抛开表象看本质。从本质概念上讲,面向对象大致有两个层次的内涵1

要了解面向对象可以首先了解一下抽象和具象的概念,这样就可以很轻松的了解什么是面向对象了。

**抽象:**抽取相同的形状,从万事万物中抽取出事物的共性,共性是表象,决定共性的是规律。

**具象:**具体的形状,通过一些具体的特征信息识别并标记出万事万物中一个具体的事物。

光看概念会比较生涩难懂,不如我们举个栗子就可以让这个概念更好的吸收。

比如我讲课的时候常说的一个例子:

就可以理解为一个抽象的概念 因为当我们提到 “ ” 这个字眼的时候,肯定是没有办法去辨识是具体的哪个人。所以说 “ ” 就是一个抽象概念 。

那什么时候是具象的概念呢?

还是以人为例子,我们提到了具体的人名的时候,就比如说当我们提到了马化腾的时候我们肯定就会知道是具体的哪一个人了。

这样我们就可以回顾一下,人就是一个类,因为一类人嘛。马化腾就是人类中实例化出来的一个对象。最终简化为:

抽象: 人 类: 人

具象:马化腾 对象:马化腾

抽象:狗 类:狗

具象:某某家的欢欢 对象:某某家的欢欢

最终再去理解抽象和具象的概念就比较生动了,抽象的事务就是类,具象的某一物体就是对象。

面向对象到底有啥用啊?

最直观的作用就是,可以分模块开发功能,一个人负责一个模块这样就可以实现多人高效率的开发。调用起来会更方便更好用。

我咋样写代码才是面向对象思想啊?

在C++当中创建一个类 比如创建一个描述人的类:

Person.h

#include <iostream>
class Person
{
private:
    //以下称为一个人类的具有的属性
    std::string name;//姓名
    std::string sex;//性别
    int age;//年龄
public:
    //以下称为一个人类所具有的行为方法
    Person(std::string name, std::string sex, int age);//构造函数 用于初始化对象 没有返回值
    void say();//自我介绍
};

Person.cpp

#include "Person.h"
Pseron::Person(std::string name, std::string sex, int age)
{
    this->name = name;
    this->sex = sex;
    this->age = age;
}

void Person::say()
{
    std::cout << "我是" << this->name << ",我今年" << this->age << "岁了。";
}

类实例化

main.cpp

#include <iostream>
#include "Person.h"
using namespace std;
int main(int argc, char *argv[])
{
	Person person("名字", "男", 20);//实例化人类到具体的人的对象
    person.say();//对象执行相应方法
    return 0;
}

在Java当中创建一个类 比如创建一个描述人的类:

Main.java

//定义一个人的类
class Person {
    //类中的属性
    private String name;
    private String sex;
    private int age;
    //构造方法
    public Person(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    //类中的行为方法
    public void say() {
        System.out.println("我是" + this.name + ",我今年" + this.age + "岁了。");
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person("名字", "男", 20);//实例化人类到具体的人的对象
        person.say();//对象执行相应方法
    }
}

面向对象的三大特性和五大原则2

当然,提到面向对象一定离不开三大特性:

  • 继承性
  • 封装性
  • 多态性

除这三大特性外还有五大原则:

  • 单一职责原则(SRP)
  • 开放封闭原则(OCP)
  • 里氏替换原则(LSP)
  • 依赖倒置原则(DIP)
  • 接口隔离原则
首先三大特性
1.继承性

继承,在继承机制下形成有层级的类,使得低层级的类可以延用高层级类的特征和方法。继承的实现方式有两种:实现继承、接口继承。

实现继承:直接使用基类公开的属性和方法,无需额外编码。

接口继承:仅使用接口公开的属性和方法名称,需要子类实现。

也就是说,继承有以下目的:

  • 复用代码,减少类的冗余代码,减少开发工作量。
  • 使得类与类之间产生关系,为多态的实现打下基础。

举个例子 张三集成老爸的资产

X爸{  
    属性:  
        股票;  
        (现金和银行存款作为养老资产,隐藏起来)  
    行为:  
        管理公司;  
}

张三的老爸不想努力了,把公司交给张三,自己的现金和银行存款已经够养老了。

X 继承 X爸{  
    属性:  
        股票;  
        (自己的现金和银行存款,隐藏起来)  
    行为:  
        管理公司;  
}
2.封装性

封装,就是将客观事物抽象为逻辑实体,实体的属性和功能相结合,形成一个有机的整体。并对实体的属性和功能实现进行访问控制,向信任的实体开放,对不信任的实体隐藏。,通过开放的外部接口即可访问,无需知道功能如何实现。

也就是说,封装主要有以下目的:

  • 可隐藏实体实现的细节。
  • 提高安全性,设定访问控制,只允许具有特定权限的使用者调用。
  • 简化编程,调用方无需知道功能是怎么实现的,即可调用。

举个例子,张三怎么和别人介绍他的女朋友

我的女朋友{  
    属性:  
        姓名;  
        (体重等信息就没必要跟别人说了,隐藏起来)  
    行为:  
        吃饭;  
        (其他的别人也不需要知道,隐藏起来)  
}
3.多态性

多态,是指一个类的同名方法,在不同情况下的实现细节不同。多态机制实现不同的内部实现结构共用同一个外部接口

也就是说,多态有以下目的:

  • 一个外部接口可被多个同类使用。
  • 不同对象调用同个方法,可有不同实现。

举个例子,拥有千万资产的张三想跟女朋友结婚了。

娶亲{  
    行为:  
        领证{挑个黄道吉日去领证};  
        摆酒{宴请各路亲戚三顿饭};  
}

张三不想像父辈那样专门挑个日子去领证,也不想请一堆不认识的亲戚吃饭。跟未婚妻商量之后,决定这么做。

张三娶亲 继承 娶亲{  
    行为:  
        领证{跟未婚妻饭后散步,顺便领证};  
        摆酒{仅仅是宴请亲人和两人各自最好的几个朋友};  
}

当别人在讨论张三是怎么娶亲的时候,可以通过娶亲这个父类,来指向张三娶亲子类,这样就可以知道张三是怎么娶亲了。

从上述可以看出,多态实现的三个必要条件是:继承、重写(子类继承父类后,对继承的方法重新定义)、父类应用指向子类对象。所以,多态的实现是基于继承的。

五大基本原则
1. 单一职责原则(Single Responsibility Principle 简称SRP)

其核心思想为:一个类,最好只做一件事,只有一个引起它的变化。

一个类,最好有且仅有一个引起它变化的原因。

举个栗子,职员类里包括了普通员工、经理、老板,那类中势必需要用if else来区分判断,而且无论是这三种职员的需求发生变化,都会影响到整个职员类。

按照“单一职责原则”,将普通员工、经理、老板分别建一个类,既不用if else加以区分,也不会在修改某个职员类别的时候影响另一个。

2. 开放封闭原则(Open - Close Principle 简称OCP)

其核心思想是:软件实体应该是可扩展的,而不可修改的。

一个类,可以扩展(添加属性和功能),但是不要修改已经写好的属性和方法。

实现开开放封闭原则的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。

打个简单的比方,X的大舅二舅都是他舅,是有血缘关系的舅舅,如果突然冒出来一个跟他有血缘关系的三舅,那也是他舅舅。同时也不能改变他大舅和二舅的亲缘关系。

3.里氏替换原则(the Liskov Substitution Principle 简称LSP)

其核心思想是:子类必须能够替换其基类。

类A是类B的父类,那么在进行调用的时候,类A可以引用类B,但是反过来不行。

其实可以粗糙地理解为,类A就是对外提供一个接口,具体的实现在类B中。

实现的方法是面向接口编程:将公共部分抽象为基类接口或抽象类,通过Extract Abstract Class,在子类中通过覆写父类的方法实现新的方式支持同样的职责。

也就是说,其实里氏替换原则是继承和多态的综合体现。

4. 依赖倒置原则(the Dependency Inversion Principle 简称DIP)

其核心思想是:依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。

在对客观事物抽象成逻辑实体时,可以先思考,同类事物的共性是什么,将这个共性作为这类事物的“高层模块”,若干不同的客观事物作为“底层模块”在依赖”高层“之后,对共性进行特定描述。

举个栗子,苹果跟西瓜都是水果,水果的共同属性是水分、糖分。在这里,”水果“作为高层模块,其属性可以在描述“苹果”和“西瓜”的时候使用,所以“苹果”“西瓜”在此是“底层模块”。

5. 接口隔离原则(the Interface Segregation Principle 简称ISP)

其核心思想是:使用多个小的专门的接口,而不要使用一个大的总接口。

接口中定义属性和需要子类实现的方法,实现类必须完全实现接口的所有方法、属性。为什么要接口隔离呢?目的有二:

  • 避免引用接口的类,需要实现其实用不到的接口方法、属性。
  • 避免当接口修改的时候,有一连串的实现类需要更改。

分离的手段主要有以下两种:1、委托分离,通过增加一个新的类型来委托客户的请求,隔离客户和接口的直接依赖,但是会增加系统的开销。2、多重继承分离,通过接口多继承来实现客户的需求,这种方式是较好的。

  • 委托分离,不直接使用原先的接口,可以用另外增加一个新的接口或类来实现需求。
  • 多重继承分离,JDK源码、Spring框架使用了这种方式,后续的JDK源码解析系列会提及,好奇的朋友可以查看集合类的结构。
总结

网上对面向对象有很多说法,有的说面向对象有四种特性六大基本原则。

多出来的一个特性是 抽象性 因为无论面向对象还是面向过程,将具体事物抽象成类,或者将问题解决过程抽象出来,这一步是少不了的。抽象已经融入到面向对象和面向过程的DNA里面了,所以个人认为,这一点是没必要分出来的,所以也就没写出来了。

多出来的基本原则是叫迪米特法则3

迪米特法则(Law of Demeter 简称LoD)

核心思想:类间解耦。

通俗来讲:一个类对自己依赖的类知道的越少越好。自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚。无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。

单纯的去看文章还是无法去理解面向对象的思想,还是需要多思考多运用从而吸收面向对象的奥义。

注解

  1. 文章出自:皮皮关的回答 链接:https://www.zhihu.com/question/31021366 ↩︎

  2. 引用自:NYforSF的文章《面向对象的三大特性和五大基本原则》 ↩︎

  3. 引用自:郑学炜的文章《面向对象三大特性六大原则》 ↩︎

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值