JavaRush /Java 博客 /Random-ZH /面向对象原则

面向对象原则

已在 Random-ZH 群组中发布
你好!你有没有想过为什么 Java 是这样设计的?从某种意义上说,您基于它们创建类 - 对象、类具有方法等。但是为什么语言的结构使得程序由类和对象组成,而不是由其他东西组成呢?为什么“对象”的概念被发明并放在最前沿?所有语言都是这样工作的吗?如果不是,它给 Java 带来了什么好处?正如您所看到的,有很多问题:)让我们在今天的讲座中尝试回答每个问题。

面向对象编程原则:

  1. 遗产
  2. 抽象
  3. 封装
  4. 多态性

什么是面向对象编程(OOP)

当然,Java 由对象和类组成是有原因的。这不是其创造者的心血来潮,甚至不是他们的发明。还有许多其他基于对象的语言。第一种此类语言称为 Simula,它于 20 世纪 60 年代在挪威发明。除此之外,Simula 还引入了“”和“方法”的概念。 面向对象编程原理 - 2
Kristen Nygaard 和 Ole Johan Dahl - Simula 的创造者
从编程标准来看,Simula 似乎是一门古老的语言,但它们与 Java 的“家族”联系是肉眼可见的。最有可能的是,您可以轻松阅读上面写的代码并一般性地解释它的作用:)
Begin
  Class Rectangle (Width, Height); Real Width, Height;

   Begin
      Real Area, Perimeter;

      Procedure Update;
      Begin
        Area := Width * Height;
              OutText("Rectangle is updating, Area = "); OutFix(Area,2,8); OutImage;
        Perimeter := 2*(Width + Height);
              OutText("Rectangle is updating, Perimeter = "); OutFix(Perimeter,2,8); OutImage;
      End of Update;

      Update;
      OutText("Rectangle created: "); OutFix(Width,2,6);
      OutFix(Height,2,6); OutImage;
   End of Rectangle;

       Rectangle Class ColouredRectangle (Color); Text Color;

  Begin
      OutText("ColouredRectangle created, color = "); OutText(Color);
      OutImage;
        End of ColouredRectangle;


         Ref(Rectangle) Cr;
   Cr :- New ColouredRectangle(10, 20, "Green");
End;
该代码示例取自文章Simula - 50 年的 OOP。正如你所看到的,Java和它的祖先并没有太大的不同:)这是因为Simula的出现标志着一个新概念的诞生——面向对象编程。维基百科给出了以下 OOP 的定义:面向对象编程(OOP)是一种基于将程序表示为对象集合的编程方法,每个对象都是特定类的实例,并且这些类形成继承层次结构。在我看来,这是非常成功的。您最近开始学习 Java,但其中几乎没有任何单词是您不熟悉的:) 如今,OOP 是最常见的编程方法。除了 Java 之外,OOP 原理还用在许多您可能听说过的流行语言中。它们是 C++(计算机游戏开发人员积极使用)、Objective-C 和 Swift(为 Apple 设备编写程序)、Python(机器学习领域需求最大)、PHP(最流行的 Web 开发语言之一)、 JavaScript(简单地说他们不做的事情)和许多其他。实际上,OOP 的这些“原则”是什么?让我们更详细地告诉你。

面向对象原则

这是基础知识。4 个主要特征共同构成了面向对象编程范式。理解它们是成为一名成功程序员的关键。 面向对象编程原理 - 3

原则1.继承

好消息是您已经熟悉 OOP 的一些原则!:) 我们已经在讲座中遇到过几次继承,并且我们有时间使用它。 继承是一种允许您基于现有(父)类描述新类的机制。在这种情况下,新类借用了父类的属性和功能。为什么继承是必要的以及它能带来什么好处?首先,代码重用。父类中描述的字段和方法可以在后代类中使用。如果所有类型的汽车都有10个公共字段和5个相同的方法,则只需将它们放在父类中即可Auto。您可以在后代类中使用它们,没有任何问题。坚实的优势:定量(更少的代码)和定性(类变得更简单)。同时,继承机制非常灵活,您可以在后代中单独添加缺少的功能(特定于特定类的某些字段或行为)。一般来说,就像在日常生活中一样:我们在某些方面与我们的父母相似,但在某些方面又与他们不同:)

原则 2. 抽象

这是一个非常简单的原则。抽象意味着突出对象的主要、最重要的特征,反之亦然——丢弃次要的、无关紧要的特征。让我们不要重新发明轮子,记住一个关于类的旧讲座中的例子。假设我们正在创建一个公司员工的文件柜。为了创建员工对象,我们编写了一个类Employee。哪些特征对于公司文件中的描述很重要?全名、出生日期、社会安全号码、纳税识别号码。但在这种类型的卡片中,我们不太可能需要他的身高、眼睛和头发颜色。公司不需要有关员工的这些信息。因此,对于该类,Employee我们将设置变量String nameint ageint socialInsuranceNumberint taxNumber,并且我们将放弃对我们来说不必要的信息,例如眼睛颜色,并将其抽象。但如果我们为一家机构创建照片模特目录,情况就会发生巨大变化。为了描述一个时装模特,身高、眼睛颜色和头发颜色对我们来说非常重要,但不需要 TIN 号码。因此,在类中Model我们创建变量String height, String hair, String eyes

原则 3:封装

我们已经遇到过。Java 中的封装意味着限制对数据的访问和更改数据的能力。正如你所看到的,它是基于“胶囊”这个词。在这个“胶囊”中,我们隐藏了一些我们不希望任何人更改的重要数据。生活中的一个简单例子。您有名字和姓氏。你认识的每个人都认识他们。但他们无权更改您的名字和姓氏。有人可能会说,这个过程被“封装”在护照办公室:你只能在那里更改你的名字和姓氏,而且只有你自己可以这样做。其他“用户”对您的名字和姓氏具有只读访问权限:) 另一个例子是您公寓中的钱。把它们放在房间中央显眼的地方并不是一个好主意。任何“用户”(来到您家的人)都可以更改您的钱数,即 接他们。最好将它们封装在保险箱中。只有您才能访问,并且只能使用特殊代码。您已经使用过的封装的明显示例是访问修饰符(privatepublic)和 getter-setter。如果age类字段Cat没有被封装,任何人都可以写:
Cat.age = -1000;
封装机制允许我们使用agesetter 方法来保护字段,在该方法中我们可以检查年龄不能为负数。

原理 4. 多态性

多态性是指将多种类型视为同一类型的能力。在这种情况下,对象的行为将根据它们所属的类型而有所不同。听起来有点复杂?现在我们就来弄清楚吧。让我们举一个最简单的例子——动物。让我们创建一个Animal具有单个方法 -voice()及其两个子方法 -Cat和的类Dog
public class Animal {

   public void voice() {

       System.out.println("Voice!");
   }
}

public class Dog extends Animal {


   @Override
   public void voice() {
       System.out.println("Bow-wow!");
   }
}

public class Cat extends Animal {

   @Override
   public void voice() {
       System.out.println("Meow!");
   }
}
现在让我们尝试创建一个链接Animal并为其分配一个对象Dog
public class Main {

   public static void main(String[] args) {

       Animal dog = new Dog();
       dog.voice();
   }
}
您认为会调用哪个方法?Animal.voice()或者Dog.voice()?类方法将被调用Dog:Woof-woof!我们创建了一个引用Animal,但该对象的行为类似于Dog. 如果有必要,他可以表现得像猫、马或其他动物。主要是将通用类型的引用分配Animal给特定后代类的对象。这是合乎逻辑的,因为所有的狗都是动物。这就是我们所说的“对象的行为会根据它们的类型而有所不同”。如果我们要创建一个对象Cat-
public static void main(String[] args) {

   Animal cat = new Cat();
   cat.voice();
}
该方法voice()将输出“喵!” “能够像处理同一类型一样处理多种类型”是什么意思?这也很容易。让我们想象一下,我们正在为动物创建一个美发沙龙。我们的美发沙龙必须能够切割所有动物,因此我们将创建一个shear()带有参数的方法(“切割”)Animal——我们要切割的动物。
public class AnimalBarbershop {

   public void shear(Animal animal) {

       System.out.println("The haircut is ready!");
   }
}
现在我们可以将shear对象Cat和对象传递给方法Dog
public static void main(String[] args) {

   Cat cat = new Cat();
   Dog dog = new Dog();

   AnimalBarbershop barbershop = new AnimalBarbershop();

   barbershop.shear(cat);
   barbershop.shear(dog);
}
这是一个明显的例子:该类AnimalBarbershop使用类型,就好像它们是相同的类型Cat一样。Dog同时,他们的行为Cat也不同Dog:他们以不同的方式使用自己的声音。

OOP出现的原因

为什么会出现这种新的编程概念——OOP?程序员拥有有效的工具:例如过程语言。是什么促使他们发明了一些全新的东西?首先,他们面临的任务的复杂性。如果 60 年前,程序员的任务看起来像是“计算这样那样的数学方程”,那么现在听起来可能像是“根据用户在游戏时刻 A、B、C、D 中做出的决定,为 STALKER 游戏实现 7 个不同的结局” 、E、F 以及这些解决方案的组合。” 正如您所看到的,过去几十年来,任务显然变得更加复杂。这意味着数据类型变得更加复杂。这是OOP出现的另一个原因。带有方程的示例可以使用普通基元轻松求解;这里不需要任何对象。但是,如果不使用您发明的某些类,甚至很难用游戏结局来描述问题。但同时,用类和对象来描述它也很容易:我们显然需要 Game 类、Stalker 类、Ending 类、Player's Decision 类、Game Moment 类等等。也就是说,即使没有开始解决问题,我们也可以轻松地在脑海中想象出解决方案的“草图”。问题日益复杂,迫使程序员将问题分成几个部分。但在过程编程中这并不那么容易。通常,程序是一棵由一堆分支组成的“树”,具有所有可能的操作选项。根据某些条件,程序沿着一个分支或另一个分支执行。对于小型程序来说,这个选项很方便,但将大型任务分成几个部分却非常困难。这种需要成为OOP出现的另一个原因。这个概念使程序员能够将程序划分为一堆类的“模块”,每个模块都完成自己的部分工作。所有相互作用的对象构成了我们程序的工作。另外,我们编写的代码可以在程序的其他地方复用,这也节省了大量的时间。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION