Image

跟PHP一起玩轉物件導向:從玩具箱到工具箱-實戰應用

第四階段:實戰應用

在這個階段,我們將透過一些實戰案例和設計模式的介紹,來加深對物件導向概念的應用理解。透過實作,我們可以將理論與實際結合,進一步提升自己的程式設計能力。

Image

實戰題目:人力資源管理功能

基本需求

在這個題目中,我們將設計一個人力資源管理系統,透過繼承來展示物件導向設計的優勢。系統中將包含兩個主要的類別:Person 和繼承自 PersonEmployee

  • Person 類別:這個類別是基礎類別,包含基本的個人資料。
    • 屬性:姓名(name)、年齡(age)、性別(gender)
    • 方法:介紹自己(introduce),輸出個人基本資訊。
  • Employee 類別:這個類別繼承自 Person,代表公司的員工。
    • 屬性:職位(position)、年薪(annualSalary)
    • 方法:顯示工作資訊(displayWorkInfo),包括職位和年薪。

進階要求

  • 多態性:添加一個可以處理多種類型員工的功能,例如 Manager 類別和 Intern 類別,它們都繼承自 Employee 但具有特定的行為或屬性。
    • Manager:除了基本員工資訊,還應該有下屬員工列表(subordinates)。
    • Intern:有實習期限(internshipDuration)和指導員工(mentor)。
  • 介面實現:定義一個 Workable 介面,包含 work() 方法。不同的員工類別將實現這個方法來描述他們的工作內容。

在實際看到程式碼之前,先自己動手練習試試看吧~

Pexels Pixabay 355948

在這UML圖中,可以很明確的知道,類別跟介面之間的關係,這樣有沒有讓你更清楚要設計的脈絡呢~

Image

上Code!!!

人員基本類別

PHP
<?php

namespace Rewrite\\ExerciseObjectOriented\\Practical;

/**
 * 表示某個人
 *
 * Class Person
 *
 * @package Rewrite\\ExerciseObjectOriented\\Practical
 *
 * @property string $name
 * @property int $age
 * @property string $gender
 */
class Person
{
    /** @var string 姓名 */
    protected string $name;

    /** @var int 年齡 */
    protected int $age;

    /** @var string 性別 */
    protected string $gender;

    public function __construct(string $name, int $age, string $gender = '')
    {
        $this->name = $name;
        $this->age = $age;
        $this->gender = $gender;
    }

    /**
     * 自我介紹
     *
     * @return string
     */
    public function introduce()
    {
        return "我的名字是{$this->name},今年{$this->age}歲,性別{$this->gender}。";
    }
}

員工類別

PHP
<?php

namespace Rewrite\\ExerciseObjectOriented\\Practical;

/**
 * 員工,繼承「人」、賦予了行為
 *
 * Class Employee
 * @package Rewrite\\ExerciseObjectOriented\\Practical
 */
class Employee extends Person
{
    protected string $position;
    protected int $annualSalary;

    /**
     * @param string $name
     * @param int $age
     * @param string $gender
     * @param string $position
     * @param int $annualSalary
     */
    public function __construct(string $name, int $age, string $gender, string $position, int $annualSalary)
    {

        parent::__construct($name, $age, $gender);

        $this->position = $position;
        $this->annualSalary = $annualSalary;
    }

    /**
     * @return string
     */
    public function displayWorkInfo(): string
    {
        return "{$this->introduce()} 我的職位是{$this->position},年薪為{$this->annualSalary}。";
    }
}

定義工作-介面

PHP
<?php

namespace Rewrite\\ExerciseObjectOriented\\Practical;

/**
 * Workable 介面
 *
 * Interface Workable
 * @package Rewrite\\ExerciseObjectOriented\\Practical
 */
interface Workable
{
    /**
     * 工作
     *
     * @return string
     */
    public function work(): string;
}

管理者類別

PHP
<?php

namespace Rewrite\\ExerciseObjectOriented\\Practical;

/**
 * 管理者
 * Manager 繼承 Employee 並實作 Workable
 *
 * Class Manager
 * @package Rewrite\\ExerciseObjectOriented\\Practical
 */
class Manager extends Employee implements Workable
{
    /** @var array */
    private array $subordinates = [];

    /**
     * 這裡的參數可以使用物件作為傳遞的內容
     * 這樣就可以直接將員工的物件加入到管理者的屬性中,並且取用對應的方法
     * 
     * @param Employee $employee
     * @return void
     */
    public function addSubordinate(Employee $employee): void
    {
        $this->subordinates[] = $employee;
    }

    /**
     * 列出所有團隊成員的基本資訊
     *
     * @return void
     */
    public function listSubordinates(): void
    {
        echo "{$this->name} 的成員有:\\n";
        foreach ($this->subordinates as $subordinate) {
            echo "\\t" . $subordinate->introduce() . "\\n";
        }
    }

    /**
     * @inheritDoc
     */
    public function work(): string
    {
        return "管理團隊和協調項目。";
    }
}

addSubordinate的方法可以傳遞 Employee的物件,這樣就可以直接將員工的物件加入到管理者的屬性中,並且取用對應的方法,這也是一種封裝的概念

實習生類別

PHP
<?php

namespace Rewrite\\ExerciseObjectOriented\\Practical;

use Rewrite\\ExerciseObjectOriented\\Practical\\Employee;
use Rewrite\\ExerciseObjectOriented\\Practical\\Workable;

class Intern extends Employee implements Workable
{
    /** @var int */
    private int $internshipDuration;

    /** @var string */
    private string $mentor;

    public function __construct($name, $age, $gender, $position, $annualSalary, $internshipDuration, $mentor)
    {

        parent::__construct($name, $age, $gender, $position, $annualSalary);

        $this->internshipDuration = $internshipDuration;
        $this->mentor = $mentor;
    }

    /**
     * @inheritDoc
     */
    public function work(): string
    {
        return "執行指派的任務和學習。";
    }
}

使用端

PHP
use Rewrite\\ExerciseObjectOriented\\Practical\\Employee;
use Rewrite\\ExerciseObjectOriented\\Practical\\Manager;

// 使用範例
$manager = new Manager("陳大文", 45, "男", "部門經理", 1200000);
$employee1 = new Employee("王小明", 30, "男", "工程師", 800000);
$employee2 = new Employee("李小華", 28, "女", "設計師", 750000);

// 添加成員
$manager->addSubordinate($employee1);
$manager->addSubordinate($employee2);

// 顯示工作資訊和下屬列表
echo $manager->displayWorkInfo() . "\\n";
$manager->listSubordinates();

// 顯示工作內容
echo $manager->work() . "\\n";

輸出內容

Image

這個題目不僅檢驗基本的物件導向設計能力,還需理解和應用多態性和介面,這對於初學者與有經驗的學習者都是一個很好的挑戰。

後記

有沒有發現實習生的類別沒有被使用到,另外再想想看,實習生的類別有沒有需要改良的地方呢~?

<= To Be Continued…