在php中使用策略模式的优点 [英] Advantages of using strategy pattern in php

查看:329
本文介绍了在php中使用策略模式的优点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎无法摆脱战略模式提供的优势。见下面的例子。

I can't seem to get my head around what advantages the strategy pattern offer. See the example below.

//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());

在上述两个示例中,策略模式将提供哪些优势,如何更好地进场?为什么要使用策略模式?

In the above two example what advantages will the strategy pattern will offer and how is it better then the first approach? Why should I use strategy pattern?

上述示例代码可能包含错误,请忽略代码。

The above example code might contain errors please ignore the code.

推荐答案

策略模式的意图是:


定义一系列算法,封装每个算法,并使它们互换。
策略允许算法与使用它的客户端独立变化。 [GoF:349]

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]

要了解这是什么意思,你必须(强调我的)

To understand what this means, you have to (emphasis mine)


考虑在设计中应该是可变的。这种方法与将重点放在重新设计的原因相反。而不是考虑什么可能会迫使更改设计,考虑您想要更改,而无需重新设计。这里的重点是封装不同的概念,许多设计模式的主题。 [GoF:29]

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]

换句话说,策略是可以在运行时插入客户端(另一个对象)的相关代码段改变其行为。要做到这一点的一个原因是防止每次添加新行为时触摸客户(参见开放封闭原则(OCP)受保护的变体)。另外,当您拥有足够复杂的算法时,将它们放入自己的课程中,有助于遵守单一责任原则(SRP)

In other words, strategies are related pieces of code you can plug into a client (another object) at runtime to change its behavior. One reason to do this, is to prevent you from having to touch the client each time a new behavior is added (cf. Open Closed Principle (OCP) and Protected Variation). In addition, when you got sufficiently complex algorithms, putting them into their own classes, helps adhering to the Single Responsibility Principle (SRP).

我发现您的问题中的例子有点不适合掌握策略模式的有用性。注册表不应该有一个 printMsg()方法,我不能很好地理解这个例子。一个更简单的例子就是我在我可以将代码包含到PHP类中?(关于策略的一部分开始于答案的一半)。

I find the example in your question somewhat ill-suited to grasp the usefulness of the Strategy Pattern. A Registry should not have a printMsg() method and I cannot make much sense of the example as such. An easier example would be the example I give in Can I include code into a PHP class? (the part where I talk about Strategy begins about halfway down the answer).

但是无论如何,在第一个代码中,注册表实现Func1和Func2的方法。因为我们假设这些是相关的算法,所以假设他们真的是 persistToDatabase()和 persistToCsv()围绕着我们的思想。我们还可以想象,在应用程序请求结束时,您可以从关闭处理程序(客户端)。

But anyway, in your first code, the Registry implements the methods Func1 and Func2. Since we assume these to be related algorithms, let's pretend they really are persistToDatabase() and persistToCsv() to have something to wrap our mind around. Let's also imagine that, at the end of an application request, you call one of these methods from a shutdown handler (the client).

但是哪种方法?那么这取决于你配置的内容,这个标志显然存储在注册表中。所以在你的客户端,你最终会得到一些类似

But which method? Well, that depends on what you configured and the flag for that is obviously stored in the Registry itself. So in your client you end up with something like

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

但是这样的switch语句是坏的(参见CleanCode:37ff)。想象你的客户请求你添加一个 persistToXml()方法。现在不仅需要更改注册表类以添加其他方法,而且还必须更改客户端以适应该新功能。这是你必须改变的两个课程,当OCP告诉我们我们的课程应该被关闭修改。

But switch statements like this are bad (cf. CleanCode:37ff). Imagine your customer requests you to add a persistToXml() method. Not only do you have to change your Registry class now to add another method, but you also have to change the client to accommodate for that new feature. That's two classes you have to change, when OCP tell us that our classes should be closed for modification.

一种改进方法是在注册表上添加一个通用的 persist()方法并移动交换机/ case进入它,所以客户端只需要调用

One way to improve that would be to add a generic persist() method on the Registry and move the switch/case into it so the client only needs to call

$registry->persist();

这更好,但仍然让我们开关/ case,它仍然迫使我们修改注册表每次我们添加一种新的方式来坚持下去。

That's better but it still leaves us with the switch/case and it still forces us to modify the Registry each time we add a new way to persist it.

现在,您也可以想象您的产品是许多开发人员使用的框架,并提出自己的持久性算法。他们如何添加他们?他们必须延长你的班级,但是他们也必须更换所使用的框架中的所有事情。或者他们只是把它们写入你的课堂,但是当你每次提供一个新的版本时,他们都必须修补课程。所以这就是蠕虫的一切。

Now also imagine your product is a framework used by many developers and they come up with their own persist algorithms. How can they add them? They'd have to extend your class but then they'd also have to replace all the occurrences in the framework where yours was used. Or they just write them into your class, but then they'd have to patch the class each time you provided a new version of it. So that's all a can of worms.

抢救的策略。由于持续算法是不同的东西,我们将封装它们。由于您已经知道如何定义一系列算法,所以我将跳过该部分,只显示最终的客户端:

Strategy to the rescue. Since the persist algorithms are the stuff that varies, we will encapsulate them. Since you already know how to define a family of algorithms, I'll skip that part and only show the resulting client:

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

很好,我们重构条件与多态性。现在您和所有其他开发人员可以根据需要的策略设置任何Persistable:

Nice, we refactored the conditional with polymorphism. Now you and all the other developers can set whatever Persistable as the desired Strategy:

$registry->setPersistable(new PersistToCloudStorage);

就是这样。没有更多的开关/箱。没有更多的注册表黑客。只需创建一个新类并设置它。该策略使算法与使用它的客户端独立变化。

And that's it. No more switch/case. No more Registry hacking. Just create a new class and set it. The Strategy lets the algorithm vary independently from clients that use it.

另请参阅

  • How does the Strategy Pattern work?
  • https://softwareengineering.stackexchange.com/questions/187378/context-class-in-strategy-pattern
  • http://sourcemaking.com/design_patterns/strategy for some more explanation.
  • https://www.youtube.com/watch?v=-NCgRD9-C6o

[GoF] Gamma,E.,Helm,R.,Johnson,R.,Vlissides,J.,Design Patterns:Elements of Reusable ObjectOriented软件,阅读,大众: AddisonWesley,1995。

[GoF] Gamma, E., Helm, R., Johnson, R., Vlissides, J., Design Patterns: Elements of Reusable Object­Oriented Software, Reading, Mass.: Addison­Wesley, 1995.

[CleanCode] Martin,Robert C. Clean Code:A Handbook of Agile Software Craftsmanship。 Upper Saddle River,NJ:Prentice Hall,2009.打印。

[CleanCode] Martin, Robert C. Clean Code: A Handbook of Agile Software Craftsmanship. Upper Saddle River, NJ: Prentice Hall, 2009. Print.

这篇关于在php中使用策略模式的优点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆