Menu
CoddyTech

Phương thức trừu tượng trong đặc tính

Thuộc phần Lập trình hướng đối tượng trong hành trình PHP của Coddy. Bài học 54 trên 91.

Trait có thể cung cấp các phương thức dùng ngay, nhưng đôi khi bạn cần lớp sử dụng trait triển khai chức năng cụ thể. Khi đó, phương thức trừu tượng trong trait sẽ hữu ích: chúng định nghĩa một hợp đồng mà lớp sử dụng trait phải thực hiện.

Khi một trait khai báo một phương thức trừu tượng, mọi lớp dùng trait đó phải triển khai phương thức ấy:

<?php
trait Notifiable {
    abstract public function getEmail(): string;
    
    public function sendNotification(string $message): void {
        echo "Sending to " . $this->getEmail() . ": $message";
    }
}

class User {
    use Notifiable;
    
    public function __construct(private string $email) {}
    
    public function getEmail(): string {
        return $this->email;
    }
}

$user = new User("john@example.com");
$user->sendNotification("Welcome!");

Đầu ra:

Sending to john@example.com: Welcome!

Trait cung cấp phương thức sendNotification() nhưng cần lớp tự triển khai getEmail(). Cách này tạo nên một mô hình mạnh mẽ, trong đó trait xử lý logic chung còn lớp triển khai đảm nhiệm các chi tiết riêng.

Nếu một lớp sử dụng trait mà không triển khai phương thức trừu tượng, PHP sẽ báo lỗi nghiêm trọng. Điều này giúp trait có thể dựa vào sự tồn tại của một số phương thức, nhờ đó code của bạn dễ dự đoán và dễ bảo trì hơn.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống định giá, trong đó các loại sản phẩm khác nhau tính giá cuối cùng theo cách khác nhau, nhưng đều dùng chung logic giảm giá thông qua một trait có phương thức trừu tượng.

Bạn sẽ tổ chức code trong ba tệp:

  • Discountable.php: Tạo một trait tên là Discountable để cung cấp chức năng giảm giá. Trait này cần có:
    • Một phương thức trừu tượng getBasePrice(): float mà các lớp sử dụng trait này phải triển khai
    • Một phương thức applyDiscount(int $percent) để tính và trả về giá sau khi áp dụng phần trăm giảm giá cho giá gốc
    • Một phương thức getFinalPrice(int $percent) để trả về chuỗi đã định dạng: "Final price: $[discounted_price]" với 2 chữ số thập phân
    Trait này xử lý toàn bộ phép tính giảm giá, nhưng cần mỗi lớp cho biết giá gốc là bao nhiêu.
  • Product.php: Tạo một lớp Product sử dụng trait Discountable. Thêm tệp trait vào. Dùng tính năng thăng cấp thuộc tính hàm khởi tạo để khai báo một $name riêng tư (chuỗi) và một $price riêng tư (số thực). Triển khai phương thức getBasePrice() cần thiết để trả về giá của sản phẩm.
  • main.php: Thêm tệp Product vào. Bạn sẽ nhận ba đầu vào: tên sản phẩm, giá và phần trăm giảm giá. Tạo một đối tượng Product và in ra hai dòng:
    • Giá gốc được định dạng như "Base: $[price]" với 2 chữ số thập phân
    • Kết quả gọi getFinalPrice() với phần trăm giảm giá

Mẫu này rất hữu ích vì mọi lớp đều có thể dùng trait Discountable, chẳng hạn như sản phẩm, dịch vụ và gói đăng ký, miễn là chúng triển khai getBasePrice(). Trait cung cấp logic giảm giá dùng chung, còn mỗi lớp xác định giá gốc của mình lấy từ đâu.

Tự làm thử

<?php

require_once 'Product.php';

// Đọc các đầu vào
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$discountPercent = intval(trim(fgets(STDIN)));

// TODO: Tạo một instance của Product với tên và giá

// TODO: In ra giá gốc theo định dạng "Base: $[price]" với 2 chữ số thập phân

// TODO: In ra kết quả gọi getFinalPrice() với phần trăm giảm giá

?>
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch PHP online