本节是《Spring Boot 实战纪实》的第11篇,感谢您的阅读,预计阅读时长3min。
算法+数据结构=程序 ——图灵奖的Pascal之父(Niklaus Wirth)
如果说算法是程序的灵魂,那么数据结构就是程序的载体。
今天就一起来探讨一下面向对象中最重要的一种数据结构——类。
有一天,产品经理给我们提了一个需求:要把大象装进冰箱里。
作为程序员的我们,就会思考把大象装进冰箱里需要几步?
经过流程梳理,我们可以大致列了几个步骤:
上面每一个步骤,我们都可以定义一个函数,每个函数可以实现一个功能。
所有函数定义好了之后,依次调用就可以了:
至此,我们便轻松愉快的完成了产品经理的需求,然后哼着小曲儿去快乐的玩耍了。
但是,过了两天产品经理又提出了更加变态的需求
面对这样“变态”的需求,如果继续使用上面的思路来实现代码功能,将会带来以下问题:
以上就是通常所说的面向过程的编程方式。正是因为面向过程的带来的诸多问题,面向对象的编程思想逐渐流行起来,并在编程界风靡至今。
没有人比我更懂面向对象。
面向对象起源于1967年在挪威设计的Simula编程语言。该语言拥有类、多态和即成等以往的编程语言没有的优良结构,被称为最早的面向对象编程语言(Object Oriented Programming Language,OOP)。后来艾伦.凯率领的团队开发的smalltalk沿用了该结构,确立了面向对象的概念。 此后,具有相同结构的C++、Objective-C、Java、C#和Ruby等诸多编程语言被相继开发出来,并延续至今。
OOP使得大规模时使得大规模的可重(chóng)用构件群的创建成为可能,这些被称为类库或框架。
而创建可重用构件群时使用的固定设计思想被提炼成设计模式。(《面向对象是怎样工作的(第2版)》)
面向对象的基本思想就是重点关注各个构件,提高构件的独立性、重用性,把构件组合起来,实现系统整体的功能。当程序发生修改时,能够将影响范围降到最低。
对象就是对事物的一种抽象描述。 现实世界中的事物,都可以用【属性】和【能力】来描述。
回到上面产品经理的将大象装进冰箱需求,用面向对象来实现,我们会先定义一个冰箱对象,它的【属性】就是当前的冷冻温度,【能力】就是开门、关门。还有一个大象对象,它的【属性】可以是大象的智商、体积。然后我们依次:
所以,当我们将程序构件化之后,一旦遇到“我要把大象装冰箱,但是门别关,敞着就行”这样的变态需求,代码不用大改,只需要将先前定义好对象和能力按照新的需求组合即可。
类就是指一类事物,对象就是指这类事物中的某个具体的个体。
类是指一类事物,类是一种归纳和总结,是一种概括,是一个抽象的概念。
比如:我们把那些具有一定知名度、一定名气的人物称之为明星,说白了,类就是对一些具有相同特性的事物进行的归纳和总结。
再比如:我们把那些用胶片或存储卡记录的人物故事影像统称为电影,所以类就是对一些具有相同特性的事物进行的归纳和总结。
你最喜欢的明星是谁? 周杰伦。
这里,明星就是类,周杰伦就是实例。
类指类型,实例指具体事物
类是面向对象的最基本的结构,与其对应
类的英文是class,含义是"种类","类型"等"同类的集合"。实例的英文是instance,含义是"具体的事物"。
比如,
面向对象本质上不是一门技术而是一种思想。
面向对象本身不是一门技术而是一种思想。只有转变了思想,你才能在日常编程中应用自如。
这里依然沿用“把大象装进冰箱”需求,从需求中分析出有两个具体的事物大象和冰箱,抽出两个对象
/** * Description: 大象类 */ @Data public class Elephant { private Object head;//头 private List<Object> feets;//四肢 private Object body;//躯干 private Object tail;//尾巴 public String toString(){ return "大象"; } }
/** * Description: 冰箱类 */ @Data public class Fridge { /** * 存储 */ public void store(Object obj) { System.out.println("把"+obj.toString()+"放进冰箱"); } /** * 开门 */ public void openTheDoor() { System.out.println("开门"); } /** * 关门 */ public void closeTheDoor() { System.out.println("关门"); } }
Java使用具体的事物,需要通过new关键字来创建这个事物的具体实例。
我们可以方便的利用Springboot来写一个单元测试:
1.实例化对象
//实例化一头大象 Elephant elephant=new Elephant();
//实体化一个冰箱 Fridge fridge=new Fridge();
2.调用冰箱的功能
fridge.openTheDoor(); fridge.store(elephant); fridge.closeTheDoor();
执行结果如下:
1、先按照名词提炼问题领域中的对象
2、对对象进行描述,其实就是在明确对象中应该具备的属性和功能
3、通过new的方式就可以创建该事物的具体对象
4、通过该对象调用它以后的功能。
面向对象思想有三大特性,即封装、继承与多态。三大特性是面向对象编程的核心,对于初学者务必加强对三大特性的理解与领会。
好比一辆汽车,你学开车的时候只需学会诸如踩油门、刹车,转方向盘即可,无需去了解它的发动机是如何发动。
封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。
是否暴露给外部,是通过访问修饰符控制,Java类中常用的访问修饰符如下:
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public |
Y | Y | Y | Y | Y |
protected |
Y | Y | Y | Y/N | N |
default |
Y | Y | Y | N | N |
private |
Y | N | N | N | N |
比如, 前面产品经理提出了狮子也装冰箱里这样的需求,于是我们提取出狮子对象。
/** * Description: 狮子对象 */ public class Lion { private Object head;//头 private List<Object> feets;//四肢 private Object body;//躯干 private Object tail;//尾巴 public String toString(){ return "狮子"; } }
按照面向对象的思想我们很快就写出了狮子类。
但是,不妨再观察一下,大象和狮子两个类是不是几乎一样,代码似乎有点重复啊~
能不能将不同类中相同的部分抽取出来公用呢? 继承特性就能做到。
继承要解决的就是代码重用的问题,利用继承性可以从已有的类继续派生出新的子类,也可以利用子类扩展出更多的功能。
大象和狮子都属于动物,因此在两个对象的基础上我们可以在抽象一个动物对象,然后大象和狮子都继承自动物。
动物类
/** * Description: 动物 */ @Data public class Animal { private Object head;//头 private List<Object> feets;//四肢 private Object body;//躯干 private Object tail;//尾巴 }
大象类继承自动物类
/** * Description: 大象类 */ @Data public class Elephant extends Animal{ public String toString(){ return "大象"; } }
狮子类继承自动物类
/** * Description: 狮子对象 */ public class Lion extends Animal{ public String toString(){ return "狮子"; } }
//实例化一头狮子 Animal lion=new Lion(); //实体化一个冰箱 Fridge fridge=new Fridge(); fridge.store(lion); fridge.store(lion); fridge.closeTheDoor();
多态是同一个行为具有多个不同表现形式或形态的能力
还是借用上面的例子来探讨,比如产品经理说动物关进冰箱之前要先叫一声,主人会根据叫声类判断关进去的是什么动物。
动物都有叫的功能
/** * Description: 动物 */ @Data public class Animal { private Object head;//头 private List<Object> feets;//四肢 private Object body;//躯干 private Object tail;//尾巴 public void Cry() { System.out.println("我被关进了冰箱!"); } }
但是不同动物叫声不同,所以需要增加各自叫的方法
/** * Description: 狮子对象 */ public class Lion extends Animal{ // 覆盖(重写)方法 public void cry() { System.out.println("吼~"); } public String toString(){ return "狮子"; } }\
/** * Description: 大象类 */ @Data public class Elephant extends Animal{ // 覆盖(重写)方法 public void cry() { System.out.println("哞~"); } public String toString(){ return "大象"; } }
测试用例走一波
以上我们通过编程实现了,不同的动物有各自的叫法,这就是多态的简单实现。
面向对象设计思想早已不是什么新鲜事物,在Java实际项目中也是主流的编程思想。
正是因为Java,C#天然就是支持面向对象的,反而很多童鞋并不能讲清楚什么是面向对象。我们只是这样在用而已...
Notes: 尽管大牛们都推崇面向对象,但并不是说面向过程就不能使用。实际项目中,还是要根据需求和场景来选择,面向对象和面向对象都是解决问题的方式,二者并不冲突。
如果本文对您有帮助,欢迎点赞支持!