OOP(面向对象)中三不准原则

it2022-05-05  150

OOP面向对象,特性继承,封装,多态。

为什么在这里我要阐述这个话题,解答依然有很多。对于OOP的理解的文章有很多,但是真正优质和正确的却是寥寥无几。认知的错误造成的结果就是误用,代码编写仍然是一个谜语一样,许多人一直无法走出迷宫,凌乱迷惘。

OOP的诞生是为了解决大型软件项目,C 语言依然也可以完成任务,但是需要的代码量让人却步。但是看看现在,一个稍微大点的项目的编码,都是非常庞大的。面向过程的编码方式是容易的,是符合数学逻辑的。面向对象编程是现实场景的一种映射,一个新的编程思想,但是我们习惯的数学题,并不习惯处理现实。面向对象是如何映射进入现实,从现实又如何回归代码编写呢,这是一个问题。

然而我们为什么不先给出正确的OOP代码,来分析该如何正确编写代码,之后再去谈现实的问题呢,这样理解也许会更好。

要想编写出好的OOP代码,首先代码好坏不是语言问题,反而有些语言有天生的优势(GO语言)但是这并不代表你会OOP,会写好OOP。

编写代码之前,有几个原则需要说明,不是六大设计原则和23种设计模式,这本身是为了大家更好的理解OOP编程,给大家的一种进阶曲线。设计原则和设计模式本事是好意,但是现在好像让大家深陷其中不能自拔,反而把OOP的继承,封装,多态忘得一干二净。所以我还是会从继承,封装,多态来阐释我将要说明的三个不准原则,为了大家编码时候犯错,从而思考如何更好的编码。

三不准原则第一个,重写函数必须调用父类函数,不准覆盖父类函数。

class Person{ func run(){ } }

class Student:Person{ override func run(){ super.run() } } 大家看到,继承重载函数run(),在子类中先调用父类run方法。

这里大家感觉不好了,不写super也行啊,子类实现自己的函数就挺好的。对的,大家说的都对,这样写也是可以的,但是如果是继承,那么子类应该“拿来用“而不是“认个爹”,所以上边的写法不应该使用继承,应该用接口。代码

interface RunInterFace{ func run() }

class Person:RunInterFace{ func run(){ } }

class Student:RunInterFace{ func run(){

} } 定义接口,这个很重要。下一个要点会着重讲。先说继承,子类重写父类方法必须调用父类函数。 还有子类继承父类属性,无论是属性还是函数,都是继承,就是那来要用的。覆盖父类方法,是错误的使用方式。 如果需要一个接口,那么就去定义一个接口。

三不准原则第二个,封装类不准定义public接口。

这个说完大家估计会很诧异,这样就不是封装,是封闭了。先来看看之前的代码

class Dog{ public func run(){ //todo } } class Cat{ public func run(){ //todo } } 这是一个很正常的public对外接口,没什么不对。是不是应该继承一个父类,然后重载呢。看看上面第一个原则。 相同的接口,应该先定义接口。

interface RunInterface{ public func run() } class Dog:RunInterface{ public func run(){ //todo } } class Cat:RunInterface{ public func run(){ //todo } } 这样写没看见有什么好处啊。这样写会涉及多态,多态调用的时候不再去指定类,而是指定需要实现的接口。 调用run接口 class Controller{ func load(m:RunInterface){ m.run() } } 在controller中调用的时候大家看到,我传入不是一个类类型,而是接口。controller只需要run起来,不管是 那个类,这样放多态调用,扩展和降低耦合。类和类之间不存在依赖关系,只通过接口交互。(面向接口编程) 虽然很多人知道面向接口编程,但是理解的不多。 还有一点,封装处处都是,写一个类就是一个封装。而不是喊着我封装一下,封装不是工具。

三不准原则最后一个,多态多接口,不准单协议。

多态有点抽象,不太好理解。我在这里告诉大家,多态就是多个interface。继承不是多态,记住继承不是多态。实例的class永远不会变,只是子类实例可以指向父类class而已。

interface RunInterface{ public func run() } interface JumpInterface{ public func jump() } class Dog:RunInterface,JumpInterface{ public func run(){ //todo } public func jump(){ //todo } } class Controller{ func load(m:RunInterface){ m.run() } func load(m:JumpInterface){ m.jump() } } 定义两个接口RunInterface,JumpInterface,Dog有两个状态,controller多态调用,调用的不是类,而是 调用某个函数,并不关心类是谁。 那为什么不把两个接口定义一个interface里面呢?可以,这个场景可以,但是不建议。实际中,协议接口多种多样, 一个类并不需要实现那么多的接口,定义到一个反而混乱职责不清。还有可选实现接口,这个最好不写,只要是接口必须实现, 不然调用的时候就必须判断是否实现协议。多个协议分组,项目中也容易分的清楚,一大坨的东西大家都不会喜欢的。


最新回复(0)