gpt4 book ai didi

php - 在php中使用策略模式的优点

转载 作者:IT王子 更新时间:2023-10-29 00:10:41 26 4
gpt4 key购买 nike

我似乎无法理解策略模式提供的优势。请参见下面的示例。

//Implementation without the strategy pattern
class Registry {

public function Func1(){
echo 'called function 1';
}

public function Func2(){
echo 'called function 2';
}

}

$client = new Registry();
$client->Func1();
$client->Func2();

//Implementation with strategy pattern
interface registry {
public function printMsg();
}

class Func1 implements registry {
public function printMsg(){
echo 'called function 1';
}
}

class Func2 implements registry {
public function printMsg(){
echo 'called function 2';
}
}

class context {

public function printMsg(Registry $class){
$class->printMsg();
}
}

$client = new context();
$client->printMsg(new Func1());
$client->printMsg(new Func2());

在上面的两个示例中,策略模式将提供哪些优势,它比第一种方法有何优势?为什么要使用策略模式?

以上示例代码可能存在错误,请忽略该代码。

最佳答案

策略模式的目的是:

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. [GoF:349]

要理解这意味着什么,你必须(强调我的)

Consider what should be variable in your design. This approach is the opposite of focusing on the cause of redesign. Instead of considering what might force a change to a design, consider what you want to be able to change without redesign. The focus here is on encapsulating the concept that varies, a theme of many design patterns. [GoF:29]

换句话说,策略是相关的代码片段,您可以在运行时将其插入客户端(另一个对象)以更改其行为。这样做的一个原因是为了防止每次添加新行为时都必须接触客户端(参见 Open Closed Principle (OCP)Protected Variation )。此外,当你有足够复杂的算法时,将它们放入自己的类中,有助于遵守 Single Responsibility Principle (SRP) .

我发现您问题中的示例不太适合理解策略模式的用途。 Registry 不应该有 printMsg() 方法,我无法理解这个例子本身。一个更简单的例子是我在 Can I include code into a PHP class? 中给出的例子(我谈论策略的部分从答案的一半开始)。

但无论如何,在您的第一段代码中,Registry 实现了方法 Func1 和 Func2。由于我们假设这些是相关算法,让我们假装它们真的是 persistToDatabase()persistToCsv() 来让我们思考一些事情。我们还想象一下,在应用程序请求结束时,您从 shutdown handler 调用这些方法之一。 (客户端)。

但是哪种方法呢?好吧,这取决于您配置的内容,并且该标志显然存储在注册表本身中。所以在你的客户中你最终会得到类似的东西

switch ($registry->persistStrategy)
{
case 'database':
$registry->persistToDatabase();
case 'csv':
$registry->persistToCsv();
default:
// do not persist the database
}

但是像这样的 switch 语句是不好的(参见 CleanCode:37ff)。假设您的客户要求您添加 persistToXml() 方法。您现在不仅必须更改 Registry 类以添加另一个方法,而且还必须更改客户端以适应该新功能。这是您必须更改的两个类,当 OCP 告诉我们应该关闭我们的类以进行修改时。

一种改进方法是在注册表上添加一个通用的 persist() 方法并将开关/案例移入其中,这样客户端只需要调用

$registry->persist();

这样更好,但它仍然留给我们 switch/case,并且它仍然迫使我们在每次添加新的持久化方法时修改注册表。

现在再假设您的产品是许多开发人员使用的框架,他们提出了自己的持久化算法。他们如何添加它们?他们必须扩展你的类,但他们也必须替换框架中使用你的类的所有事件。或者他们只是将它们写入您的类(class),但每次您提供新版本时他们都必须修补类(class)。所以这就是一堆蠕虫。

救援策略。由于持久算法是变化的东西,我们将封装它们。由于您已经知道如何定义一系列算法,因此我将跳过该部分,仅展示生成的客户端:

class Registry
{
public function persist()
{
$this->persistable->persist($this->data);
}
public function setPersistable(Persistable $persistable)
{
$this->persistable = $persistable
}
// other code …

很好,我们refactored the conditional with polymorphism .现在您和所有其他开发人员可以将任何 Persistable 设置为所需的策略:

$registry->setPersistable(new PersistToCloudStorage);

就是这样。没有更多的开关/外壳。不再有注册表黑客攻击。只需创建一个新类并进行设置即可。该策略让算法独立于使用它的客户端而变化。

另见

尾注:

[GoF] Gamma, E.、Helm, R.、Johnson, R.、Vlissides, J.,设计模式:可重用面向对象软件的元素,马萨诸塞州雷丁:AddisonWesley,1995 年。

[CleanCode] Martin, Robert C. Clean Code:敏捷软件工艺手册。新泽西州上马鞍河:Prentice Hall,2009 年。打印。

关于php - 在php中使用策略模式的优点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17721623/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com