这篇文章主要介绍“编程语言中面向对象的介绍以及使用方法”,在日常操作中,相信很多人在编程语言中面向对象的介绍以及使用方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”编程语言中面向对象的介绍以及使用方法”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
什么是面向对象
面向对象(Object Oriented)是软件开发方法。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。 面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。 百度百科
依据以上解释,初学者很难理解什么是面向对象,大概做个简单解释,因为面向对象的概念非常大,所以大家有什么意见或建议请与我联系。
面向对象是一个方法论,采用这种方法论,软件开发人员能够更好的进行开发工作;
面向对象是区别于面向过程的一个方法论,关于面向过程请看第2点;
Object的中文含义是“目标”、“物体”等,面向对象,即站在一个Object的角度去思考;
面向对象的语言都是高级语言,主流有Java\C++\Python\Objective-C\JavaScript\Python\PHP等(排名不分先后);
在面向对象中,现实世界的一个事物即为一个对象,各自有其不同属性(形状\颜色等),不同行为(功能)。使用编程语言把这些属性和行为描述成一个抽象的对象,且不同的编程语言有不同的表达方式。
面向过程
“面向过程”(Procedure Oriented)是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是封装、继承、类。百度百科
有人说,女朋友/男朋友就是对象。显然,这个说法是正确的。因为,每个人都有一些属性,比如:姓名、性别、身高、年龄、身份证号等等;也有一些行为,例如:走路、吃饭、工作等。
万事万物都是一个对象,人们描述一个事物,经常通过一些名称、形状和很多特征去描述,比如 是人、直立行走、会使用工具等,那么这个过程,是自然语言描述一个事物的过程,在面向对象编程中,同样可以使用相似的语言描述成一个事物,那么这个事物代表人,以JavaScript代码为例:
女朋友是被丈母娘生下来的,那么编程中的对象,也是被创建出来的,以上方法就是在JavaScript中创建一个对象的过程。
面向对象程序设计(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。任何一个模型都不可能反映客观事物的一切具体特征,只能对事物特征和变化规律的一种抽象,且在它所涉及的范围内更普遍、更集中、更深刻地描述客体的特征。通过建立模型而达到的抽象是人们对客体认识的深化。百度百科
通俗来讲,我们把现实世界的一个事物,使用编程语言描述成编程世界中的对象,然后再去使用这些对象进行对更高一级世界的构建的过程,就是面向对象编程。
我们描述出什么是学生,什么是老师,什么是课程,可以构成一个课程管理系统;同样,我们描述出商品,描述出用户,描述出订单,可以构成一个网上商城。
封装
把一个对象的属性和行为,封装到一个不可分割的独立实体,把自己可以被外界访问的通过受保护的接口公开,即属性私有,方法公开。
上面的内容太官方,封装,用一台电脑比喻,包含主板、CPU、内存条、硬盘、显卡等等,这些是不可被人直接去操作的。那么我们同样能够通过键盘、鼠标、显示器等输入输出设备去访问操作这台电脑。
我们无法直接去访问其被包起来的内容,这些属于电脑私有的,是不可以被访问的,当然我们可以通过输入输出设备去操作这台电脑,这部分是对外开放的,你可以进行访问的。
听起来就像是电脑的外壳把它的核心组件给封装了起来,然后通过一些插口来接入键盘鼠标,你进行操作。没错,这就是封装。
class Computer{ String cpu; int memory; String gpu; String hardDisk public void powerOn(){ //开机 } public void powerOff(){ //关机 } }
继承
子类继承父类,可以使得子类具有父类的方法和属性,无需重写父类的方法即可调用。子类同样可以重写父类的方法使得父类的方法具有不同的的功能。子类可以追加新的方法,使得子类的功能更丰富。
虽然不是儿子继承父亲遗产,但是同样,儿子可以拥有父亲的资产。子类继承了父类,拥有父类的方法和属性。
在编程中的继承,是因为抽象的原因导致的,比如,英语老师和数学老师,物理老师,都可以继承 "老师" 这个父类,而老师,是在这个过程中属于一个抽象的概念,那么三位老师都有教学的这个功能,同样都有职业证书、职称等等属性。这个特性也会造成下一个面向对象的特性——多态。
但是不一样的是,物理老师可以修电表,英语老师可以和外国人交流,数学老师同样能用数学方法解决生活中的问题。显然他们都是老师的情况下,每个老师也有自己的超能力。
class Teacher{ String title;//职称 String subject;//所授课程 void teach(){ //教学 } } class EnglishTeacher extends Teacher{ private String englishLevel;//英语等级 void teach(){ System.out.println("I am teaching English") } void talkToForeigners(){ //和外国人对话 } }
多态
不同对象对同一个操作可以做出不同的反应,产生不同的执行结果。可以通过指向基类的指针,来调用实现派生类中的方法。
老师都可以教学,那么不同的老师,所教的内容不一样,数学老师教我们数学,英语老师教我们英语,而物理老师教我们物理。
此处我们当然是需要调用父类(老师)的教学方法,但是因为不同的子类重写了父类的方法,所以当通过调用父类的方法的时候,才会产生不同的结果。
向上造型是产生多态的基石,比如我们可以这么写 Teacher teacher = new MathTeacher() 来实现向上造型,此时我们调用 teacher.teach() 方法,则会调用到数学老师的 teach() 方法。
关于抽象
抽象是指从具体事物抽出、概括出它们共同的方面、本质属性与关系等,而将个别的、非本质的方面、属性与关系舍弃的思维过程。
抽象并没有被列到面向对象三大特征中,相对来说,个人认为这个是面向对象的基本方法,所有面向对象的特征都基于,先进行抽象,才能构建出对象。
我们在编程过程中会尽可能的使用抽象思维,将一个或者一类现实世界的事物,使用面向对象语言,变成编程中的对象。
比如刚才我们把三个不同的老师抽象成老师,事实上我们还可以把老师归并到学校的工作人员,把学校工作人员归并为社会工作人员,更可以把社会工作人员归并为人类。当然,越是抽象的对象,其属性和方法就会更少,以为共同点更少了。
开闭原则
开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查,单元测试以及诸如此类的用以确保产品使用质量的过程。百度百科-开闭原则
应该对于扩展是开放的,但是对于修改是封闭的
这句话不好理解,但是可以看一个例子:
/** * <p> mapper基类 </p> * * @author Calvin * @date 2019/11/07 * @since */ public abstract class BaseMapper<BaseEntity>{ /** * 新增或保存 * @param entity */ public void saveOrUpdate(BaseEntity entity){ String id = entity.getId(); BaseEntity exists = null; if(StringUtils.isNotEmpty(id) && (exists = this.findById(id)) == null){ this.save(entity); }else{ this.update(entity); } } /** * 根据ID查找,抽象方法 * @param id * @return */ abstract BaseEntity findById(String id); /** * 新增 * @param entity */ abstract void save(BaseEntity entity); /** * 修改 * @param entity */ abstract void update(BaseEntity entity); }
通过定义一个baseMapper,以后有新增的Mapper中有saveOrUpdate方法,我们只需要令其实现BaseMapper, 使得 其对应的Bean去继承 BaseEntity,这样我们就能够横向进行扩展。
class UserMapper extends BaseMappper{ @Override public User findById(String id){ // select * from user where id = #{id} } @Override public void save(User user){ // insert into user ...... } @Override public void update(User user){ //update user set .... where id = #{user.id} } }
另外有三点约束:
第一,通过接口或者抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法;
第二,参数类型、引用对象尽量使用接口或者抽象类,而不是实现类;
第三,抽象层尽量保持稳定,一旦确定即不允许修改。
找到一篇帖子,个人认为是融会贯通了:https://www.liangzl.com/get-article-detail-133084.html
接口隔离
客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。百度百科-接口隔离原则
也就是说,如果一个类,实现了一个拥有三个方法的接口,而这个类本身只需要使用其中两个,那么,此时违背了接口隔离的原则。
interface Interface1 { void function1(); void function2(); void function3(); }
class A implements Interface1{ @Override public void function1(){ //被需要的 } @Override public void function2(){ //被需要的 } @Override public void function3(){ //不被需要的 } }
此时需要对接口进行改造,一般意义上是根据功能或者其领域,拆分成不同的接口。
interface Interface1 { void function1(); void function2(); }
interface Interface2 { void function3(); }
拆分成两个接口后,A类只实现Interface1,不需要实现Interface2,就可以了,代码略,此时就算是简单遵循了接口隔离。
接口隔离要注意的点:
接口要高内聚。什么是高内聚?高内聚就是提高接口、类、模块的处理能力,减少对外的交互,就比如一个人,你告诉下属“到奥巴马的办公室偷一个XX文件”,然后就听到下属就坚定的口吻回答你“好的,保证完成!”,然后一个月后还真的把XX文件放到你的办公桌了,这种不讲任何条件、立刻完成任务的行为就是高内聚的表现。具体到接口隔离原则就是要求在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险也就越少,同时也有利于降低成本。
定制服务。一个系统或系统内的模块之间必然会有耦合,有耦合就要相互访问的接口(并不一定就是Java中定义的Interface,也可能是一个类或者是单纯的数据交换),我们设计时就需要给各个访问者(也就是客户端)定制服务,什么是定制服务?单独为一个个体提供优良优良的服务。我们在做系统设计时也需要考虑对系统之间或模块之间的定义要采用定制服务,采用定制服务就必然有一个要求就是:只提供访问者需要的方法,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
接口尽量小,但是要有限度。接口的设计粒度是越小系统越灵活,这是不争的事实,但是这就带来成接口数量过多,使设计结构的复杂化,开发难度增加,维护性降低,这不是一个项目或产品所期望看到的。所以一定要适度。
本部分转载自:https://blog.csdn.net/u012361379/article/details/88101102
职责单一
它规定一个类应该只有一个发生变化的原因。百度百科-单一职责原则
此处的一个类只能有一个发生变化的原因
此处是指,由于业务场景等原因导致的变化,而不是代码运行期间的变化。解释略有一点含糊,导致笔者在很早之前对此不是特别懂。
class UserMapper{ User findOne(String id){ //TODO } User insertOne(User user){ //TODO } void updateById(User user){ //TODO } User generateUser(String username, String password){ User user = new User(); user.setId(UUID.generateUUID().toString()); user.setUsername(username); user.setPassword(password); insertOne(user) } }
以上是一个反例,这个类当中存在一个生成学生的方法,还有插入新增查询的方法,生成学生的方法依赖于新增。
此时无论是生成学生的方法发生变化,还是插入学生的方法发生变化,都可能导致另一个方法(以至于这个类)发生变化。
代码进行修改
class UserMapper{ User findOne(String id){ //TODO } User insertOne(User user){ //TODO } void updateById(User user){ //TODO } } class UserGenerator{ UserMapper userMapper; UserGenerator(UserMapper userMapper){ this.userMapper = userMapper; } User generateUser(String username, String password){ User user = new User(); user.setId(UUID.generateUUID().toString()); user.setUsername(username); user.setPassword(password); userMapper.insertOne(user) } }
里式替换
任何基类可以出现的地方,子类一定可以出现。 百度百科-里式替换原则
里氏代换原则是很多其它设计模式的基础。它和开放封闭原则的联系尤其紧密。违背了里氏代换原则就一定不符合开放封闭原则。还是Teacher那个代码:
public TeacherTest{ public static void main(String [] args){ Teacher teacher = new MathTeacher(); teacher.teach(); MathTeacher mathTeacher = new MathTeacher(); mathTeacher.teach(); } }
两个测试方法执行结果会完全一样。
一:子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法.【核心观念】
二:子类中可以增加自己特有的方法.
三:前置条件放大,子类在重载父类的已实现方法时,方法的前置条件(形参)范围应该比父类更加宽松.
四:后置条件缩小,子类在实现父类的抽象方法时,方法的后置条件(返回值)范围应该比父类更加严格或相同.
此部分原文链接:https://blog.csdn.net/hongxiancheng/article/details/83049746
依赖倒置
程序要依赖于抽象接口,不要依赖于具体实现。高层次的模块不应该依赖低层次的模块,二者应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
有认识过SpringMVC的人一定懂这个:
public interface UserService{ User create(HashMap args); }
@Mapper public interface UserMapper{ void insert(User user); }
public class UserServiceImpl implements UserService{ @Autowride private UserMapper userMapper; public User create(HashMap args){ User user = UserParser.fromMap(args); userMapper.insert(user); } }
这就是典型的依赖倒置,调用方不用关心UserMapper具体实现是什么,只需依赖此接口,就能完成自己的业务逻辑。
依赖倒置原则假定所有的具体类都是会变化的;
为避免对类的直接调用,依赖倒置可能会使得项目产生更多的类;
面向接口编程
会使你更好的利用依赖倒置原则;
6. 迪特米法则
迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。百度百科-迪特米法则
一个女孩子
public class Girl{ private BoyFriend boyFriend; public void getBoyFriend(){ return this.boyFriend(); } }
女孩的男朋友
public class BoyFriend{ public void receiveMessage(String message){ //response } }
女孩的闺蜜
public class BosomFriend{ private Girl girl; BosomFriend(Girl girl){ this.girl = girl; } public void talk(){ String message = "I am so cold!"; BoyFriend boyFriend = girl.getBoyFriend(); boyFriend.receiveMessage(message); } }
此时,你的闺蜜直接告诉你男朋友的她很冷,显然违背了迪特米法则,那么你应该怎么做,以后他们的任何通信必须通过你。
public class Girl{ private BoyFriend boyFriend; public void getBoyFriend(){ return this.boyFriend(); } //把你跟你男朋友说话的方法暴露出来 public void talkToBoyFriend(String message){ if(StringUtils.isNotEmpty(message)){ //过滤一下说的什么内容 boyFriend.receiveMessage(message); }else{ //当然不能告诉男朋友了 } } }
以后他们交流就可以通过你交流,这样避免他们私下里沟通。当闺蜜类不再依赖男朋友类的时候,就遵从了迪特米原则。
public class BosomFriend{ private Girl girl; BosomFriend(Girl girl){ this.girl = girl; } public void talk(){ String message = "I am so cold!"; girl.talkToBoyFriend(message); } }
尽量减少对象之间的交互,从而减小类之间的耦合。简言之,一定要做到:低耦合,高内聚。
在做系统设计时,不要让一个类依赖于太多的其他类,需尽量减小依赖关系。
1、本文简单介绍了面向对象和其核心概念;
2、简单通过代码,演示了面向对象的特征;
3、通过demo详细介绍了面向对象的SOLID五大原则和迪特米法则;
到此,关于“编程语言中面向对象的介绍以及使用方法”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。