php设计模式应用
如果您认为第一模式是Singleton,那么您将被解雇! Singleton模式已经过时,不希望甚至讨厌。
让我们看一下这几天PHP世界中最常用的5种设计模式 。
厂
要构建对象时,应使用工厂。 是的- 构建而不是创建 。 您不希望有一个工厂来创建一个新对象。 构建对象时,首先创建它,然后对其进行初始化。 通常,它需要执行多个步骤并应用某些逻辑。 这样,将所有内容放在一个地方并在需要以相同方式构建新对象时重新使用它就很有意义。 基本上,这就是工厂模式的重点。
最好为您的工厂提供一个接口,并使您的代码依赖于此,而不要依赖于具体的工厂。 这样一来,您可以在需要时轻松地用另一家工厂替换。
接下来,我们使用以下类实现工厂接口:
interface FriendFactoryInterface {
public function create () : Friend
}
那是非常简单但功能强大的设计模式!
战略
它用于隐藏执行操作所需的算法的实现细节。 有了策略,客户可以在不知道实际实现的情况下选择所需的算法,并将其应用于执行操作。
假设我们需要创建一个将数据从一个数据源传输到另一个数据源的库。 例如,我们需要将数据从数据库传输到csv文件,或从电子表格传输到json文件。 你会怎么做?
首先,我们需要创建各自的策略以从存储中读取数据。 我们称它们为Readers 。 接下来,我们需要创建相应的策略以将数据写入存储。 我们称他们为作家 。
因此,我们将有2位读者从数据库或电子表格中读取数据。 因此,我们将有2个Writer将数据写入csv文件或json文件。
重要提示:将与我们的策略合作的客户不应在意其实施。 因此,我们还应该为我们的策略定义接口。 这样,客户将只知道由策略接口定义的方法,并且只能与它们一起使用,而幕后发生的事情不是它的问题。
最后,我们需要创建一个客户端,该客户端将根据需要从何处和何处传输数据来选择所需的策略。
让我们来看看所有的动作:
interface ReaderInterface {
public function start () : void ;
public function read () : array ;
public function stop () : void ;
}
interface WriterInterface {
public function start () : void ;
public function write (array $data) : void ;
public function stop () : void ;
}
class DatabaseReader implements ReaderInterface {
...
}
class SpreadsheetReader implements ReaderInterface {
...
}
class CsvWriter implements WriterInterface {
...
}
class JsonWriter implements WriterInterface {
...
}
class Transformer {
...
public function transform (string $from, string $to) : void {
$reader = $this ->findReader($from);
$writer = $this ->findWriter($to);
$reader->start();
$writer->start();
try {
foreach ($reader->read() as $row) {
$writer->write($row);
}
} finally {
$writer->stop();
$reader->stop();
}
}
...
}
如您所见,作为我们策略的客户的转换器实际上并不关心它的实现方式。 它关心的只是由我们的策略界面定义的方法。
适配器
它用于将外部接口转换为公共接口。 假设在项目中使用以下类从某个存储中获取数据。
class Storage {
private $source;
public function __constructor (AdapterInterface $source) {
$this ->source = $source;
}
public function getOne (int $id) : ? object {
return $this ->source->find($id);
}
public function getAll (array $criteria = []) : Collection {
return $this ->source->findAll($criteria);
}
}
请注意, 存储并不直接与源一起使用,而是与源适配器一起使用。
此外,存储对具体适配器一无所知。 它仅指适配器接口。 因此,所提供适配器的具体实现对于它来说是一个完整的黑匣子。
这是适配器接口的示例
interface AdapterInterface {
public function find (int $id) : ? object ;
public function findAll (array $criteria = []) : Collection ;
}
现在,假设我们使用一些库来访问MySQL数据库。 该库规定了它自己的接口,它看起来如下所示:
$row = $mysql->fetchRow(...);
$data = $mysql->fetchAll(...);
如您所见,我们不能像把它那样集成到我们的torage中 。 我们需要为其创建一个适配器,如下所示:
class MySqlAdapter implements AdapterInterface {
...
public function find (int $id) : ? object {
$data = $this ->mysql->fetchRow([ 'id' => $id]);
// some data transformation
}
public function findAll (array $criteria = []) : Collection {
$data = $this ->mysql->fetchAll($criteria);
// some data transformation
}
...
}
之后,我们可以将其注入到存储中 ,如下所示:
$storage =new Storage( new MySqlAdapter($mysql));
如果以后我们决定使用另一个库来代替该库,则只需像上面一样为该库创建另一个适配器,然后将新适配器注入到Storage中 。 如您所见,为了使用不同的库来从数据库获取数据,我们不需要在Storage类中进行任何操作。 这就是适配器设计模式的强大功能!
观察者
它用于通知系统其余部分的某些事件。 为了更好地了解这种模式的好处,让我们回顾一下同一问题的两种解决方案。
假设我们需要创建剧院来向评论家放映电影。 我们使用当前方法定义剧院类。 在放映电影之前,我们要向评论家的手机发送消息。 然后,在电影的中间,我们希望将电影停止播放5分钟,以便评论家休息一下。 最后,电影结束后,我们想请评论家留下他们的反馈意见。
让我们看一下代码中的样子:
class Theater {
public function present (Movie $movie) : void {
$critics = $movie->getCritics();
$this ->messenger->send($critics, '...' );
$movie->play();
$movie->pause( 5 );
$this ->progress->break($critics)
$movie->finish();
$this ->feedback->request($critics);
}
}
它看起来干净而且很有前途。
现在,一段时间后,老板告诉我们在开始播放电影之前,我们也要关闭灯。 另外,在电影中间,当它暂停时,我们要显示广告。 最后,电影结束后,我们要开始自动清洁房间。
好吧,这里的问题之一是为了实现这一点,我们需要修改Theatre类,这违反了SOLID原则。 特别是它破坏了打开/关闭 原则。 而且,这种方法将使戏剧课依赖于一些附加服务,这也不是一件好事。
如果我们把事情颠倒了怎么办。 与其给剧院类增加越来越多的复杂性和依赖性,我们不如将其复杂性分散到整个系统中,从而减少作为一个奖励的剧院类的依赖性。
这是实际的样子:
class Theater {
public function present (Movie $movie) : void {
$this ->getEventManager()
->notify( new Event(Event::START, $movie));
$movie->play();
$movie->pause( 5 );
$this ->getEventManager()
->notify( new Event(Event::PAUSE, $movie));
$movie->finish();
$this ->getEventManager()
->notify( new Event(Event::END, $movie));
}
}
$theater = new Theater();
$theater
->getEventManager()
->listen(Event::START, new MessagesListener())
->listen(Event::START, new LightsListener())
->listen(Event::PAUSE, new BreakListener())
->listen(Event::PAUSE, new AdvertisementListener())
->listen(Event::END, new FeedbackListener())
->listen(Event::END, new CleaningListener());
$theater->present($movie);
正如你所看到的, 本方法变得非常简单。 它不在乎课外会发生什么。 它只是执行应做的事情,并将事实通知系统的其余部分。 对这些事实感兴趣的任何人都可以收听相应的事件并得到有关它们的通知,并做其必须做的事情。
使用这种方法,添加其他复杂性也变得非常容易。 您要做的就是创建一个新的侦听器,并将所需的逻辑放在这里。
希望您发现观察者模式有用。
装饰器
当您要在运行时调整对象的行为时,可以使用它,从而减少冗余继承和类数。 您可能会问为什么我完全需要它? 好吧,用示例可以更好地解释它。
假设我们有Window和Door类,它们都实现OpenerInterface 。
interface OpenerInterface {
public function open () : void ;
}
class Door implements OpenerInterface {
public function open () : void {
// opens the door
}
}
class Window implements OpenerInterface {
public function open () : void {
// opens the window
}
}
窗户和门的打开行为相同。 现在,我们需要其他门窗用的附加功能,将告诉用户外面的温度 ,当他们打开 车门或车窗 。 我们可以通过继承来解决此问题,如下所示:
class SmartDoor extends Door {
public function open () : void {
parent ::open();
$this ->temperature();
}
}
class SmartWindow extends Window {
public function open () : void {
parent ::open();
$this ->temperature();
}
}
到目前为止,我们总共有4个课程。 但是,使用Decorator模式,我们只能使用3个类来解决此问题。 这是如何做:
class SmartOpener implements OpenerInterface {
private $opener;
public function __construct (OpenerInterface $opener) {
$this ->opener = $opener;
}
public function open () : void {
$this ->opener->open();
$this ->temperature();
}
}
$door = new Door();
$window = new Window();
$smartDoor = new SmartOpener($door);
$smartWindow = new SmartOpener($window);
我们引入了一种新型的开启器 ,其作用类似于代理,但其上还具有其他功能。 这就是窍门。
如果您在任何类型的开发项目中需要帮助,我也可以为您提供有关项目的咨询。 我是最受好评的自由职业者。 您可以直接在 Upwork 上雇用我 。 你也可以 雇用我 自由职业者 。 如果您有任何评论,问题或建议,请随时在下面的评论部分中发布它们!
翻译自: https://hackernoon.com/the-5-most-common-design-patterns-in-php-applications-7had322l
php设计模式应用