预计阅读时间: 6 分钟
设计模式不是我们可以复制并插入到程序中的代码,就像我们可以使用标准函数或库一样。设计模式是能够解决特定问题的一般概念。基本上是一个模型,我们可以遵循其详细信息并实施适合我们程序实际情况的解决方案。
模型经常与算法混淆,因为这两个概念都描述了一些已知问题的典型解决方案。虽然算法 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