理解 OOP 中的抽象

Understanding abstraction in OOP

我正在研究面向对象的概念,抽象概念基本上被描述为对用户隐藏实现。因此,如果 class 中有一个成员函数,并且我们为某个任务调用该函数,抽象表示用户不应该关心事情是如何完成的,而应该只知道正在完成什么。但即使在非面向对象的编程风格中,如果我们编写一个函数,整个任务也可以通过简单地调用一个函数来完成。它不也遵循抽象逻辑吗?或者,OOP中的抽象和函数式编程有什么区别吗?

并不是您调用的函数提供了抽象,而是调用它的庄园。例如,您可能有一个允许您编写一行文本的函数:

void writeLine(string fileName, string value)

但这并不是从您正在写入文件的事实中抽象出来的。抽象版本不需要调用者提供 fileName 参数,因为它特定于函数的特定实现。相反,你会:

void writeLine(string value)

并且文件名是使用另一种机制提供的,例如class 的构造函数参数,如果您正在使用 OOP 并调用 writeLine 方法,或者在功能情况下,您可能会柯里化原始函数以创建抽象版本。

在面向对象编程中,我们通常从继承和多态的角度来思考抽象。

让我们考虑一下Writer接口

interface Writer {
    void write(byte[] bytes)
}

此界面允许用户写入...某物。什么,我们并不特别担心。我们可以有多个版本:

class FileWriter implements Writer

class StringWriter implements Writer

class LogWriter implements Writer

class MySuperCustomWriter implements Writer

我们在哪里写并不重要,可以是 FileString、套接字或任何地方。我们想要做的就是写一些东西。这让我们可以这样写代码:

public class MyBusinessLogic {

    private final Writer writer;

    public MyBusinessLogic(Writer writer) {
        this.writer = writer;
    }

    void someBusinessLogic() {
        // .. 
        writer.write(someStuff);
    }
}

我们这里有一些需要编写的业务逻辑。通过使用接口,我们的业务逻辑不再依赖于任何特定的写法。它只是获取一些能够进行一些写入的对象。我们可以将它传递给我们的任何示例编写器,并确保它能正常工作,因为我们感兴趣的是编写的行为,而不是实现。

通过这样做,业务逻辑不依赖于文件系统、网络或其他任何东西。

快速封装示例

type
    public class DateTimeClass
       private 
          Era: integer;
          Culture: integer;
          Year: integer;
          Month: integer;
          Day: integer;

      protected
           Integer function getYear ( );

           // other functions

           procedure setYear ( );

          // other functions
      public
          procedure AssignOccidentalDate
               (NewYear: integer; NewMonth: integer;
                    NewDay : integer);
   end;

   ...

   var Date: DateTimeClass;

  Date.AssignOccidentalDate (2019, 07, 27);
  ...

您只能访问 "public" 声明。