預計閱讀時間: 6 minuti
設計模式不是我們可以複製並插入程式中的程式碼,就像我們可以使用標準函數或函式庫一樣。設計模式是能夠解決特定問題的一般概念。基本上是一個模型,我們可以遵循其詳細資訊並實施適合我們程序實際情況的解決方案。
模型經常與演算法混淆,因為這兩個概念都描述了一些已知問題的典型解決方案。雖然演算法 defi如果總是有一組明確的操作可以實現某個目標,那麼模型就是解決方案的更高層次的描述。應用於兩個不同程式的相同模型的程式碼可能會不同。
打個比方,我們可以想到烹飪食譜:兩者都有明確的步驟來實現目標。然而,模型更像是一個項目,你可以看到它的結果和特點,但具體的實現順序取決於我們編寫程式碼的人。
大多數模式都被非常正式地描述,以便人們可以在許多上下文中重現它們。讓我們看看下面模型描述中存在的元素:
程式設計師可以在不知道設計模式存在的情況下開發軟體。許多人這樣做,因此他們在不知情的情況下實施了一些計劃。但那我們為什麼要花時間學習它們呢?
設計模式在整個設計系統的複雜性、詳細程度和適用範圍方面有所不同。
以此類推,我們可以透過安裝幾個紅綠燈或建造一個帶有地下行人通道的整個多層立交橋來使十字路口更安全。
最基本的低階模型通常稱為 成語 。它們通常僅適用於單一程式語言。
最通用和最高級的模型是 建築模型 。開發人員幾乎可以用任何語言實作這些模式。與其他模式不同,它們可用於設計整個應用程式的架構。
此外,所有型號都可以根據其用途進行分類 試過了 或目的。三個主要類別是:
正面 是一種結構設計模式,為函式庫、框架或任何其他複雜的類別集提供簡化的介面。
假設我們需要使軟體能夠基於屬於複雜程式庫或框架的大量物件來運作。通常,我們需要初始化所有這些物件、追蹤依賴關係、以正確的順序執行方法等等。
結果,類別的業務邏輯將與第三方類別的實作細節緊密耦合,使得它們難以理解和管理。
一 facade
是一個為包含許多活動部件的複雜子系統提供簡單介面的類別。 A facade
與直接使用子系統相比,可能提供有限的功能。然而,它只包含客戶真正關心的功能。
有一個 facade
當我們需要將應用程式與具有數十種功能的複雜庫集成,但我們只需要其功能的一小部分時,它非常有用。
例如,將貓的有趣短影片上傳到社交媒體的應用程式可能會使用專業的影片轉換庫。然而,我們真正需要的是一個具有單一方法的類 encode(filename, format)
。創建這樣一個類別並將其連接到視訊轉換庫後,我們將擁有第一個類 facade
.
例如,呼叫中心的電話接線員就像 facade
。事實上,當我們撥打商店的電話服務進行電話訂購時,接線員就是我們的 facade
面向商店的所有服務和部門。營運商為訂購系統、支付網關和各種送貨服務提供簡單的語音介面。
想想 正面 作為一些複雜子系統的簡單適配器。 Facade
將複雜性隔離在單一類別中,並允許其他應用程式程式碼使用簡單的介面。
在這個例子中, Facade
對客戶端程式碼隱藏了 YouTube API 和 FFmpeg 程式庫的複雜性。客戶端在 Facade 上使用一個簡單的方法,而不是使用數十個類別。
<?php
namespace RefactoringGuru\Facade\RealWorld;
/**
* The Facade provides a single method for downloading videos from YouTube. This
* method hides all the complexity of the PHP network layer, YouTube API and the
* video conversion library (FFmpeg).
*/
class YouTubeDownloader
{
protected $youtube;
protected $ffmpeg;
/**
* It is handy when the Facade can manage the lifecycle of the subsystem it
* uses.
*/
public function __construct(string $youtubeApiKey)
{
$this->youtube = new YouTube($youtubeApiKey);
$this->ffmpeg = new FFMpeg();
}
/**
* The Facade provides a simple method for downloading video and encoding it
* to a target format (for the sake of simplicity, the real-world code is
* commented-out).
*/
public function downloadVideo(string $url): void
{
echo "Fetching video metadata from youtube...\n";
// $title = $this->youtube->fetchVideo($url)->getTitle();
echo "Saving video file to a temporary file...\n";
// $this->youtube->saveAs($url, "video.mpg");
echo "Processing source video...\n";
// $video = $this->ffmpeg->open('video.mpg');
echo "Normalizing and resizing the video to smaller dimensions...\n";
// $video
// ->filters()
// ->resize(new FFMpeg\Coordinate\Dimension(320, 240))
// ->synchronize();
echo "Capturing preview image...\n";
// $video
// ->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(10))
// ->save($title . 'frame.jpg');
echo "Saving video in target formats...\n";
// $video
// ->save(new FFMpeg\Format\Video\X264(), $title . '.mp4')
// ->save(new FFMpeg\Format\Video\WMV(), $title . '.wmv')
// ->save(new FFMpeg\Format\Video\WebM(), $title . '.webm');
echo "Done!\n";
}
}
/**
* The YouTube API subsystem.
*/
class YouTube
{
public function fetchVideo(): string { /* ... */ }
public function saveAs(string $path): void { /* ... */ }
// ...more methods and classes...
}
/**
* The FFmpeg subsystem (a complex video/audio conversion library).
*/
class FFMpeg
{
public static function create(): FFMpeg { /* ... */ }
public function open(string $video): void { /* ... */ }
// ...more methods and classes... RU: ...дополнительные методы и классы...
}
class FFMpegVideo
{
public function filters(): self { /* ... */ }
public function resize(): self { /* ... */ }
public function synchronize(): self { /* ... */ }
public function frame(): self { /* ... */ }
public function save(string $path): self { /* ... */ }
// ...more methods and classes... RU: ...дополнительные методы и классы...
}
/**
* The client code does not depend on any subsystem's classes. Any changes
* inside the subsystem's code won't affect the client code. You will only need
* to update the Facade.
*/
function clientCode(YouTubeDownloader $facade)
{
// ...
$facade->downloadVideo("https://www.youtube.com/watch?v=QH2-TGUlwu4");
// ...
}
$facade = new YouTubeDownloader("APIKEY-XXXXXXXXX");
clientCode($facade);
Ercole Palmeri