PL/SQL - 面向对象编程

你好,有抱负的程序员们!今天,我们将踏上一段激动人心的旅程,探索PL/SQL中的面向对象编程(OOP)世界。如果你是编程新手,不用担心——我会成为你友好的向导,一步一步地解释所有内容。那么,让我们开始吧!

PL/SQL - Object Oriented

什么是面向对象编程?

在我们开始之前,让我们了解一下OOP是什么。想象你正在用乐高积木建造一座房子。每一块积木代表一个对象,你可以以各种方式组合这些积木,创造出更复杂的结构。这就是OOP在编程中做的事情——它允许我们创建和操作代表现实世界实体的对象。

实例化一个对象

现在,让我们学习如何在PL/SQL中创建(或“实例化”)一个对象。把它想象成在你的编程世界中激活一个乐高角色!

CREATE OR REPLACE TYPE person AS OBJECT (
name VARCHAR2(50),
age NUMBER,
MEMBER FUNCTION say_hello RETURN VARCHAR2
);

CREATE OR REPLACE TYPE BODY person AS
MEMBER FUNCTION say_hello RETURN VARCHAR2 IS
BEGIN
RETURN '你好,我的名字是 ' || name || ' 我今年 ' || age || ' 岁。';
END;
END;

DECLARE
john person;
BEGIN
john := person('John Doe', 30);
DBMS_OUTPUT.PUT_LINE(john.say_hello());
END;

在这个例子中,我们创建了一个person对象类型,包含两个属性(nameage)和一个方法(say_hello)。然后我们实例化了一个对象john并调用了它的say_hello方法。

成员方法

成员方法就像我们的对象拥有的特殊技能。让我们为我们的person对象添加另一个方法:

CREATE OR REPLACE TYPE person AS OBJECT (
name VARCHAR2(50),
age NUMBER,
MEMBER FUNCTION say_hello RETURN VARCHAR2,
MEMBER PROCEDURE have_birthday
);

CREATE OR REPLACE TYPE BODY person AS
MEMBER FUNCTION say_hello RETURN VARCHAR2 IS
BEGIN
RETURN '你好,我的名字是 ' || name || ' 我今年 ' || age || ' 岁。';
END;

MEMBER PROCEDURE have_birthday IS
BEGIN
age := age + 1;
DBMS_OUTPUT.PUT_LINE(name || ' 现在是 ' || age || ' 岁了。');
END;
END;

DECLARE
john person;
BEGIN
john := person('John Doe', 30);
john.have_birthday();
DBMS_OUTPUT.PUT_LINE(john.say_hello());
END;

在这里,我们添加了一个have_birthday过程,它将人的年龄增加1。这就像给我们的乐高角色赋予了庆祝生日的技能!

使用Map方法

Map方法用于比较对象。它就像给我们的对象一张特殊的身份证,帮助我们排序。让我们看看它是如何工作的:

CREATE OR REPLACE TYPE person AS OBJECT (
name VARCHAR2(50),
age NUMBER,
MAP MEMBER FUNCTION get_id RETURN NUMBER
);

CREATE OR REPLACE TYPE BODY person AS
MAP MEMBER FUNCTION get_id RETURN NUMBER IS
BEGIN
RETURN age;
END;
END;

DECLARE
john person := person('John Doe', 30);
jane person := person('Jane Smith', 25);
BEGIN
IF john > jane THEN
DBMS_OUTPUT.PUT_LINE(john.name || ' 更年长');
ELSE
DBMS_OUTPUT.PUT_LINE(jane.name || ' 更年长');
END IF;
END;

在这个例子中,我们使用age作为比较的ID。这就像根据乐高角色的身高来比较它们!

使用Order方法

Order方法是比较对象的另一种方式,但它比Map方法提供了更多的灵活性。它就像有一个特殊的裁判来比较我们的乐高角色:

CREATE OR REPLACE TYPE person AS OBJECT (
name VARCHAR2(50),
age NUMBER,
ORDER MEMBER FUNCTION compare(p person) RETURN INTEGER
);

CREATE OR REPLACE TYPE BODY person AS
ORDER MEMBER FUNCTION compare(p person) RETURN INTEGER IS
BEGIN
IF self.age < p.age THEN
RETURN -1;
ELSIF self.age > p.age THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
END;

DECLARE
john person := person('John Doe', 30);
jane person := person('Jane Smith', 30);
BEGIN
IF john > jane THEN
DBMS_OUTPUT.PUT_LINE(john.name || ' 更年长');
ELSIF john < jane THEN
DBMS_OUTPUT.PUT_LINE(jane.name || ' 更年长');
ELSE
DBMS_OUTPUT.PUT_LINE('他们同龄');
END IF;
END;

这个方法允许我们定义自定义的比较逻辑。当我们想根据多个属性比较对象时,这特别有用。

PL/SQL对象的继承

继承就像为我们的对象创建家谱。我们可以创建继承现有对象属性和方法的新对象类型。让我们看看如何:

CREATE OR REPLACE TYPE employee UNDER person (
job_title VARCHAR2(50),
salary NUMBER,
MEMBER FUNCTION get_annual_salary RETURN NUMBER
);

CREATE OR REPLACE TYPE BODY employee AS
MEMBER FUNCTION get_annual_salary RETURN NUMBER IS
BEGIN
RETURN salary * 12;
END;
END;

DECLARE
emp employee := employee('Alice Johnson', 35, 'Manager', 5000);
BEGIN
DBMS_OUTPUT.PUT_LINE(emp.say_hello());
DBMS_OUTPUT.PUT_LINE('年薪: $' || emp.get_annual_salary());
END;

在这里,employeeperson的子类型,继承了它的属性和方法,同时添加了自己的。就像创建一个特殊的乐高角色,它不仅可以做普通角色能做的一切,还能做得更多!

PL/SQL中的抽象对象

抽象对象就像其他对象的蓝图。它们定义了一个结构,但不能直接实例化。让我们创建一个抽象对象:

CREATE OR REPLACE TYPE shape AS OBJECT (
name VARCHAR2(50),
MEMBER FUNCTION get_area RETURN NUMBER
) NOT INSTANTIABLE NOT FINAL;

CREATE OR REPLACE TYPE circle UNDER shape (
radius NUMBER,
OVERRIDING MEMBER FUNCTION get_area RETURN NUMBER
);

CREATE OR REPLACE TYPE BODY circle AS
OVERRIDING MEMBER FUNCTION get_area RETURN NUMBER IS
BEGIN
RETURN 3.14159 * radius * radius;
END;
END;

DECLARE
c circle := circle('我的圆形', 5);
BEGIN
DBMS_OUTPUT.PUT_LINE('面积 of ' || c.name || ': ' || c.get_area());
END;

在这个例子中,shape是一个抽象对象,为所有形状定义了一个通用结构。circleshape的具体实现。就像有一个通用的乐高指导手册(抽象对象),然后根据它创建特定的乐高模型!

就是这样!我们已经覆盖了PL/SQL中面向对象编程的基础。记住,熟能生巧,所以不要害怕用这些概念进行实验。快乐编码!

方法 描述
构造函数 创建并初始化一个对象
成员函数 返回一个值,可以在SQL语句中使用
成员过程 执行一个动作,但不返回值
Map方法 用于比较对象,基于单个值
Order方法 用于比较对象,允许自定义比较逻辑
FINAL方法 不能在子类型中被覆盖
NOT INSTANTIABLE方法 必须在子类型中被覆盖后才能实例化对象

Credits: Image by storyset