[Object-Oriented + Ada] Bài 3 – Polymorphism & Type’Class

Lúc này chúng ta có trường Name và phương thức Greet của Coder đã được kế thừa lại từ Person, nhưng lại chỉ có thể hoạt động tốt nếu như object được truyền vào ở vị trí tham số thứ hai là kiểu Person.Entity; Còn nếu là kiểu Coder.Entity thì trình biên dịch sẽ báo

Lúc này chúng ta có trường Name và phương thức Greet của Coder đã được kế thừa lại từ Person, nhưng lại chỉ có thể hoạt động tốt nếu như object được truyền vào ở vị trí tham số thứ hai là kiểu Person.Entity; Còn nếu là kiểu Coder.Entity thì trình biên dịch sẽ báo lỗi chứ không có sự chuyển đổi kiểu dữ liệu ngầm định được thực hiện.

Như vậy là chúng ta đang cần thêm khả năng định kiểu dữ liệu cho một biến có thể đại diện được cho bất kỳ kiểu object nào trong cùng cây phả hệ hay hệ thống kế thừa. Và đây là một sự biểu thị của Tính Đa Hình Encapsulation, hay chính xác hơn là Sub-typing Polymorphism. Các kiểu Polymorphism còn lại không thuộc về OOP nói riêng thì chúng ta đã nói đến ở bài viết về Overloading Sub-programGenerics trong Sub-Series Procedural trước đó.

Type’Class

Khi sử dụng thuộc tính Class được gắn với các kiểu dữ liệu bằng cú pháp Type'Class thì chúng ta sẽ nhận được một kiểu dữ liệu tổng hợp Union biểu trưng cho tất cả các kiểu tagged trong cùng mô hình cây kế thừa tính từ vị trí của chính kiểu Type đó.

Ví dụ nếu chúng ta sử dụng Person.Entity'Class để định kiểu cho một biến nào đó thì biến đó sẽ có thể nhận lưu một object thuộc kiểu Person.Entity hoặc tất cả các kiểu trong dòng kế thừa tính từ Person.Entity trở đi.

Vậy nếu như chúng ta sửa lại định nghĩa của phương thức Greet trong package Person với tham số đứng sau sử dụng kiểu Person.Entity'Class thì chúng ta sẽ có thể sử dụng một object Person.Entity để Greet một object Coder.Entity mà không gặp phải thông báo lỗi.

package Person is

   type Entity is tagged;
   type Class is access all Entity'Class;
   
   -- ...

   procedure Greet (Self: in Entity; Other: in Entity'Class);

end Person;

Ở đây chúng ta cũng đồng thời cập nhật định nghĩa của kiểu con trỏ Person.Class thành access all Entity'Class. Như vậy khi khởi tạo các object mới, chúng ta có thể sử dụng một biến con trỏ kiểu này để lưu các object Coder.Entity hoặc các kiểu khác trong cùng cây kế thừa nếu cần thiết.

Overriding Method

Nói về phương thức Greet được định nghĩa tại Person, tham số Other : in Entity'Class lúc này đã có khả năng biểu thị cho nhiều kiểu object khác nhau và như vậy chúng ta đã có thể nói rằng đây là một biểu hiện của Tính Đa Hình Polymorphism. Tuy nhiên để biểu thị ở bề mặt kết quả hoạt động thì chúng ta có thể sẽ muốn cung cấp thêm một phiên bản định nghĩa mở rộng của Greet trong Coder.

with Person; use Person;

package Person.Coder is

   -- ...
   
   procedure Greet (Self: in Entity; Other: in Person.Entity'Class);

end Person.Coder;

Giả sử hành động Greet ở đây, chúng ta sẽ chỉ cần sử dụng thêm duy nhất tên của người đối diện trong câu chào "Hi, " & Other.Name. Nếu vậy kiểu object mô phỏng người đối diện sẽ chỉ cần có ít nhất trường Name đã được định nghĩa tại Person và vì vậy nên để có logic hoạt động đầy đủ nhất chúng ta có thể định kiểu tham số OtherPerson.Entity'Class.

with Ada.Text_IO; use Ada.Text_IO;
with Person; use Person;

package body Person.Coder is

   procedure Greet
      ( Self : in Entity
      ; Other : in Person.Entity'Class )
   is -- local
   begin
      Person.Entity (Self).Greet (Other);
      Put_Line ("A fellow Coder");
   end Greet;

end Person.Coder;

Để gọi tới định nghĩa của Greet đã có sẵn trong Person thì ở đây chúng ta cần chuyển kiểu của Self thành Person.Entity qua thao tác như trên. Và lúc này chúng ta đã có thể thử lại code tương tác tại main, lần này chúng ta sẽ thử sử dụng kiểu con trỏ Person.Class thay cho Coder.Class của biến Me để kiểm tra luôn hoạt động của kiểu con trỏ access all Person.Entity'Class.

with Ada.Text_IO; use Ada.Text_IO;
with Person; use Person;
with Person.Coder; use Person.Coder;

procedure Main is
   Me, Lucy : Person.Class;
begin
   Me := new Coder.Entity'
      ( Name => "Semi Dev_   "
      , Intellect => 0 );

   Lucy := new Person.Entity'
      ( Name => "Lucy        " );

   Put_Line ("-- Message - - - -");
   Me.Greet (Lucy.all);

   Put_Line ("-- Message - - - -");
   Lucy.Greet (Me.all);
end Main;
alr run

-- Message - - - -
Hi, Lucy
I'm Semi Dev_
A fellow Coder
-- Message - - - -
Hi, Semi Dev_
I'm Lucy

[Object-Oriented + Ada] Bài 4 – Abstraction & Inteface

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ