更新时间:2021-08-25 10:49:51 来源:极悦 浏览938次
面向对象编程 (OOP) 是一种依赖于类和对象概念的编程范式。它用于将软件程序构建为简单、可重用的代码蓝图(通常称为类),用于创建对象的单个实例。有许多面向对象的编程语言,包括 JavaScript、C++、Java和Python。
一类是用于创建更具体的,具体对象的抽象蓝图。类通常代表广泛的类别,例如Car或Dog共享属性。这些类定义了此类型的实例将具有哪些属性,例如color,但不定义特定对象的这些属性的值。
类还可以包含函数,称为仅对该类型的对象可用的方法。这些函数在类中定义,并执行一些对特定类型对象有帮助的操作。
例如,我们的Car类可能有一个方法repaint来改变color我们汽车的属性。这个函数只对 type 的对象有用Car,所以我们在Car类中声明它,从而使它成为一个方法。
类模板用作创建单个对象的蓝图。这些代表抽象类的特定示例,例如myCar或goldenRetriever。对于类中定义的属性,每个对象都可以具有唯一值。
例如,假设我们创建一个类,Car以包含所有汽车必须具备的特性color,brand和model。然后我们创建一个Car类型对象的实例,myCar来代表我的特定汽车。
然后我们可以设置类中定义的属性值来描述我的汽车,而不会影响其他对象或类模板。
然后我们可以重用这个类来表示任意数量的汽车。
OOP 将复杂事物建模为可重现的简单结构
可重用,OOP 对象可以跨程序使用
允许通过多态实现特定于类的行为
更容易调试,类通常包含所有适用的信息
安全,通过封装保护信息
让我们考虑一个现实世界的问题,从概念上设计一个 OOP 软件程序。
想象一下,经营一个有数百只宠物的狗训练营,您必须跟踪每只宠物的姓名、年龄和参加日期。您将如何设计简单、可重复使用的软件来为狗建模?
有数百只狗,为每只狗编写唯一代码将是低效的。下面我们将看到对象rufus和fluffy.
//Object of one individual dog
var rufus = {
name: "Rufus",
birthday: "2/1/2017",
age: function() {
return Date.now() - this.birthday;
},
attendance: 0
}
//Object of second individual dog
var fluffy = {
name: "Fluffy",
birthday: "1/12/2019",
age: function() {
return Date.now() - this.birthday;
},
attendance: 0
}
正如你在上面看到的,两个对象之间有很多重复的代码。该age()函数出现在每个对象中。由于我们希望每只狗都有相同的信息,因此我们可以使用对象和类来代替。
将相关信息组合在一起形成类结构使代码更短且更易于维护。
在养狗示例中,以下是程序员如何考虑组织 OOP:
为所有狗创建一个父类,作为所有狗都将拥有的信息和行为(方法)的蓝图,无论类型如何。
在通用父蓝图下创建子类来表示狗的不同子类别。
向子类添加独特的属性和行为以表示差异
从代表该子组中的狗的子类创建对象
下图展示了如何设计 OOP 程序:将相关数据和行为组合在一起形成一个简单的模板,然后为专门的数据和行为创建子组。
该Dog班是一个通用模板,只包含有关数据,并适用于所有的狗行为的结构。
然后我们创建两个子类Dog,HerdingDog和TrackingDog。它们具有Dog( bark())的遗传行为,但也具有该亚型狗独有的行为。
最后,我们创建该HerdingDog类型的对象来表示单个狗Fluffy和Maisel。
我们还可以创建这样的对象Rufus,该对象适合广泛的类 ,Dog但不适合HerdingDog或TrackingDog。
接下来,我们将深入了解上面使用的 OOP 程序的每个基本构建块:
班级
对象
方法
属性
班级
简而言之,类本质上是用户定义的数据类型。类是我们为方法和属性的结构创建蓝图的地方。单个对象是从该蓝图实例化或创建的。
类包含属性字段和行为方法。在我们的Dog类示例中,属性包括name& birthday,而方法包括bark()和updateAttendance()。
下面的代码片段演示了如何Dog使用JavaScript语言对类进行编程。
class Dog {
constructor(name, birthday) {
this.name = name;
this.birthday = birthday;
}
//Declare private variables
_attendance = 0;
getAge() {
//Getter
return this.calcAge();
}
calcAge() {
//calculate age using today's date and birthday
return Date.now() - this.birthday;
}
bark() {
return console.log("Woof!");
}
updateAttendance() {
//add a day to the dog's attendance days at the petsitters
this._attendance++;
}
}
请记住,该类是用于建模狗的模板,并且对象是从代表单个现实世界事物的类实例化的。
对象
当然 OOP 包括对象!对象是使用特定数据创建的类的实例,例如在下面的代码片段中Rufus是Dog类的实例。
class Dog {
constructor(name, birthday) {
this.name = name;
this.birthday = birthday;
}
//Declare private variables
_attendance = 0;
getAge() {
//Getter
return this.calcAge();
}
calcAge() {
//calculate age using today's date and birthday
return Date.now() - this.birthday;
}
bark() {
return console.log("Woof!");
}
updateAttendance() {
//add a day to the dog's attendance days at the petsitters
this._attendance++;
}
}
//instantiate a new object of the Dog class, and individual dog named Rufus
const rufus = new Dog("Rufus", "2/1/2017");
当新类Dog被调用时:
创建了一个名为的新对象 rufus
构造函数运行name&birthday参数,并分配值
属性
属性是存储的信息。属性在Class模板中定义。当对象被实例化时,单个对象包含存储在 Attributes 字段中的数据。
对象的状态由对象属性字段中的数据定义。例如,在宠物营地,一只小狗和一只狗可能受到不同的对待。生日可以定义对象的状态,并允许软件以不同的方式处理不同年龄的狗。
方法
方法代表行为。方法执行动作;方法可能会返回有关对象的信息,或更新对象的数据。方法的代码在类定义中定义。
当单个对象被实例化时,这些对象可以调用类中定义的方法。在下面的代码片段中,bark方法是在Dog类中定义的,bark()方法是在Rufus对象上调用的。
class Dog {
//Declare protected (private) fields
_attendance = 0;
constructor(name, birthday) {
this.namee = name;
this.birthday = birthday;
}
getAge() {
//Getter
return this.calcAge();
}
calcAge() {
//calculate age using today's date and birthday
return this.calcAge();
}
bark() {
return console.log("Woof!");
}
updateAttendance() {
//add a day to the dog's attendance days at the petsitters
this._attendance++;
}
}
方法经常修改、更新或删除数据。方法不必更新数据。例如,该bark()方法不会更新任何数据,因为 barking 不会修改类的任何属性Dog:name或birthday。
该updateAttendance()方法增加了Dog参加宠物训练营的一天。出勤属性对于在月底跟踪计费所有者很重要。
方法是程序员促进可重用性并将功能封装在对象中的方式。这种可重用性在调试时是一个很大的好处。如果出现错误,只有一个地方可以找到并修复它,而不是很多地方。
下划线 in_attendance表示该变量是受保护的,不应直接修改。该updateAttendance()方法用于更改_attendance.
面向对象编程的四大支柱是:
继承:子类继承父类的数据和行为
封装:在对象中包含信息,只暴露选定的信息
抽象:只公开访问对象的高级公共方法
多态性:许多方法可以完成相同的任务
遗产
继承允许类继承其他类的特性。换句话说,父类将属性和行为扩展到子类。继承支持可重用性。
如果在父类中定义了基本属性和行为,则可以创建子类来扩展父类的功能,并添加额外的属性和行为。
例如,牧羊犬具有独特的放牧能力。换句话说,所有的牧羊犬都是狗,但并非所有的狗都是牧羊犬。我们通过HerdingDog从父类创建一个子类来表示这种差异Dog,然后添加独特的herd()行为。
继承的好处是程序可以创建一个通用的父类,然后根据需要创建更具体的子类。这简化了整体编程,因为子类无需Dog多次重新创建类的结构,而是自动获得对其父类中功能的访问权限。
在下面的代码片段中,子类HerdingDog继承了bark父类Dog的方法,子类添加了一个额外的方法,herd()。
//Parent class Dog
class Dog{
//Declare protected (private) fields
_attendance = 0;
constructor(namee, birthday) {
this.name = name;
this.birthday = birthday;
}
getAge() {
//Getter
return this.calcAge();
}
calcAge() {
//calculate age using today's date and birthday
return this.calcAge();
}
bark() {
return console.log("Woof!");
}
updateAttendance() {
//add a day to the dog's attendance days at the petsitters
this._attendance++;
}
}
//Child class HerdingDog, inherits from parent Dog
class HerdingDog extends Dog {
constructor(name, birthday) {
super(name);
super(birthday);
}
herd() {
//additional method for HerdingDog child class
return console.log("Stay together!")
}
}
请注意,HerdingDog该类没有bark()方法的副本,它继承bark()了父Dog类中定义的方法。
当代码调用fluffy.bark()方法时,该bark()方法会沿着子类到父类的链向上走,以找到bark定义方法的位置。
//Parent class Dog
class Dog{
//Declare protected (private) fields
_attendance = 0;
constructor(namee, birthday) {
this.name = name;
this.birthday = birthday;
}
getAge() {
//Getter
return this.calcAge();
}
calcAge() {
//calculate age using today's date and birthday
return this.calcAge();
}
bark() {
return console.log("Woof!");
}
updateAttendance() {
//add a day to the dog's attendance days at the petsitters
this._attendance++;
}
}
//Child class HerdingDog, inherits from parent Dog
class HerdingDog extends Dog {
constructor(name, birthday) {
super(name);
super(birthday);
}
herd() {
//additional method for HerdingDog child class
return console.log("Stay together!")
}
}
//instantiate a new HerdingDog object
const fluffy = new HerdingDog("Fluffy", "1/12/2019");
fluffy.bark();
在 JavaScript 中,继承也称为原型设计。原型对象充当另一个对象从中继承属性和行为的模板。可以有多个原型对象模板,创建一个原型链。
这与父/子继承的概念相同。继承是从父到子的。在我们的示例中,所有三只狗都可以吠叫,但只有 Maisel 和 Fluffy 可以放牧。
该herd()方法在子HerdingDog类中定义,因此从该类实例化的两个对象Maisel和可以访问该方法。FluffyHerdingDogherd()
Rufus 是从父类实例化的对象Dog,因此 Rufus 只能访问该bark()方法。
封装
封装意味着将所有重要信息包含在一个对象内部,并且只将选定的信息暴露给外部世界。属性和行为由类模板内的代码定义。
然后,当从类中实例化对象时,数据和方法被封装在该对象中。封装将内部的软件代码实现隐藏在一个类中,隐藏了内部对象的内部数据。
封装需要将某些字段定义为私有字段,将某些字段定义为公共字段。
私有/内部接口:方法和属性,可从同一类的其他方法访问。
公共/外部接口:方法和属性,也可以从类外部访问。
抽象
抽象意味着用户仅与对象的选定属性和方法进行交互。抽象使用简化的高级工具来访问复杂的对象。
用简单的事物来表示复杂性
对用户隐藏复杂的细节
抽象是使用简单的类来表示复杂性。抽象是封装的扩展。例如,您不必了解发动机如何工作来驱动汽车的所有细节。
驾驶员只使用一小部分工具:如油门踏板、刹车、方向盘、闪光灯。工程对司机是隐藏的。为了让汽车运转起来,很多部件都必须在引擎盖下工作,但是将这些信息暴露给驾驶员会很危险地分散注意力。
抽象也起着重要的安全作用。通过只显示选定的数据片段,并且只允许通过类访问数据和通过方法修改数据,我们可以保护数据不被暴露。继续以汽车为例,您不希望在驾驶汽车时打开油箱。
抽象的好处总结如下:
简单、高级的用户界面
复杂代码被隐藏
安全
更轻松的软件维护
代码更新很少改变抽象
多态性
多态意味着设计对象来共享行为。使用继承,对象可以覆盖共享的父行为,具有特定的子行为。多态允许同一个方法以两种方式执行不同的行为:方法覆盖和方法重载。
以上就是极悦小编介绍的"面向对象编程:OOP深入解释",希望对大家有帮助,想了解更多可查看Java教程。极悦在线学习教程,针对没有任何Java基础的读者学习,让你从入门到精通,主要介绍了一些Java基础的核心知识,让同学们更好更方便的学习和了解Java编程,感兴趣的同学可以关注一下。
0基础 0学费 15天面授
Java就业班有基础 直达就业
业余时间 高薪转行
Java在职加薪班工作1~3年,加薪神器
工作3~5年,晋升架构
提交申请后,顾问老师会电话与您沟通安排学习