設計一個合格的類,不是一上來就寫 class {},而是要先進行「使用者視角」的假設:假設這個類已經存在,對象已經具備所有屬性與方法,那麼在實際業務中我們希望如何調用它?這就是面向對象設計的核心——介面先行,實作在後。
業務需求是「縮小圖片並輸出」。被操作的核心實體是「圖片」,因此對象即為 Image。由於圖片不唯一,實例化時必須指定來源:
$img = new Image('photo.jpg');
一張圖片天生具備的屬性:寬度、高度、類型。實例化後應立即可讀取:
echo $img->width;
echo $img->height;
echo $img->type;
若直接允許 $img->width = 200 修改屬性,會誤導使用者以為原圖尺寸被改變。實際上縮略圖是「基於原圖生成新圖並儲存」,原圖屬性應為唯讀。更符合語義的操作流程:
$img = new Image('photo.jpg'); // 實例化原圖
$img->width; $img->height; // 讀取原圖尺寸計算比例
$img->resize(200, 200)->save('thumb.jpg'); // 指定尺寸另存為
resize() 返回 $this 實現鏈式調用。save() 接收目標路徑,執行實際縮放與儲存。若將即將生成的縮略圖視為對象,則實例化時為空白狀態,需載入基準圖、調整尺寸、最後儲存:
$thumb = new Thumbnail('thumb.jpg'); // 指定輸出檔名
$thumb->load('photo.jpg'); // 載入原圖
$thumb->width = 200; $thumb->height = 200;
$thumb->save(); // 生成並寫入磁碟
此視角更貼近「建構輸出物」的直覺,但第一種「以原圖為對象」的設計更符合領域模型慣例。
<?php
class Image {
public $width = 0;
public $height = 0;
public $type = 0;
private $sourcePath = '';
private $targetWidth = 0;
private $targetHeight = 0;
public function __construct($path) {
$info = getimagesize($path);
$this->width = $info[0];
$this->height = $info[1];
$this->type = $info[2];
$this->sourcePath = $path;
}
public function resize($w, $h) {
$this->targetWidth = $w;
$this->targetHeight = $h;
return $this; // 支援鏈式調用
}
public function save($destPath) {
// 根據 $this->type 載入原圖 (imagecreatefromjpeg/png/gif)
// 使用 imagecopyresampled 縮放
// 輸出至 $destPath (imagejpeg/png/gif)
// 釋放資源
}
}
getimagesize() 同步取得寬、高、類型,屬性即時可用。$targetWidth、$targetHeight 僅供內部方法使用,避免外部污染。resize() 返回 $this,使 $img->resize(...)->save(...) 如自然語言般流暢。這樣一個符合 OOP 思想、介面清晰、易於維護擴展的類別就完成了。實際專案中可進一步加入錯誤處理、支援更多圖片格式、引入介面定義等增強健壯性。