Advantages of using strategy pattern in php

前端 未结 6 807
耶瑟儿~
耶瑟儿~ 2021-02-02 13:42

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 Regist         


        
相关标签:
6条回答
  • 2021-02-02 14:16

    There's a library and a symfony bundle here:

    https://packagist.org/packages/pugx/godfather

    0 讨论(0)
  • 2021-02-02 14:20

    Strategy pattern helps in abstracting out the algorithmic approach for doing some particular work. Suppose you want to sort an array of numbers via different algorithms, In this case it is better to apply a strategy pattern than to tightly couple the algorithm with your code.

    In the class where you are instantiating the class composed of strategy you instantiate the strategy class reference by passing it to the constructor of composed class.

    This way you we are programming to an interface and not implementation and therefore at any point of time we can add more classes to the hierarchy of strategy class and pass the same to the class composed of strategy

    Kindly go through the following link

    0 讨论(0)
  • 2021-02-02 14:27

    Basically Strategy is for grouping functionality across multiple classes. Oh and you have a typo in your code

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

    With the name of the interface of the type hinting. To be more clear let me show you a small example. Imagine you have an Iphone and an Android What's their common point? One is They are both phones. you could create an interface like this

    interface Telephone {
        public function enterNumber();
        public function call();
        public function sentTextMessage();
    }
    

    and implement the interface in each of your telephones:

    class Iphone implements Telephone {
         // implement interface methods
    }
    
    class Android implement Telephone {
    
    }
    

    and you can have a service attached to all phones like a GPS on you car: and be sure that if you plug a telephone (usually with the interface BlueTooth). you could do something like this:

    class carGps{
       public function handFreeCall(Telephone $tel){
           $this->amplifyVolume($tel->call());
       }
    }
    
    
    $tomtom = new CarGps();
    $tomtom->handFreeCall(new Iphone());
    //or if you like to:
    $tomtom->handFreeCall(new Android());
    

    as an application developer, you'll be able to use your handFreeCall on every phones that implements the Telephone interface without breaking your code, because you'll know that the telephone is capable of calling.

    Hope I helped.

    0 讨论(0)
  • 2021-02-02 14:34

    The intent of the Strategy pattern is to:

    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)

    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]

    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).

    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).

    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
    }
    

    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.

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

    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 …
    

    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.

    Also see

    • 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

    End Notes:

    [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. Print.

    0 讨论(0)
  • 2021-02-02 14:35

    Often, examples are somewhat odd, describing ducks, cats or else. Here is an example of Strategy Pattern used in displaying alerts. (Extending the Gordon's answer).

    1. Interface for the methods, that vary (i.e., alert format in the case):

    require_once("initialize/initialize.php");
    interface alert{
    public function alert($message);
    };
    

    2. Methods, that implement alert interface.

    class alertBorderBullet implements alert{
    public function alert($message){
    $alert = "<p style='border:1px solid #eee; padding:4px; padding-left:8px; padding-right:8px; border-left:4px solid #FC0; margin-top:8px; margin-bottom:8px; color:#888'>".$message."</p>";
    return $alert;
    }
    };
    
    class alertOrangeBgnd implements alert{
    public function alert($message){
    $alert = "<p style='color:#fff; background-color:#ff9c3a; padding:4px; padding-left:8px; padding-right:8px; margin-top:8px; margin-bottom:8px; border-left:4px solid #e471bd;'>".$message."</p>";
    return $alert;
    }
    };
    
    class alertRed implements alert{
    public function alert($message){
    $alert = "<p style='color:#c11; background-color:#efefef; padding:4px; padding-left:12px; padding-right:8px; margin-top:8px; margin-bottom:8px;'>".$message."</p>";
    return $alert;
    }
    };
    

    3. Messenger, to separate alert method setting and getting from other objects in a project.

    class alertMessenger{
    protected $_alert;
    public function setAlertType(alert $alert){$this->_alert = $alert;}
    public function returnAlert($message){return $this->_alert->alert($message);}
    };
    

    4. A random project object that will use "alerting" in different ways.

    class randomObject{
    public $alert;
    public function __construct(){
        $this->alert = new alertMessenger;
    }
    // More code here...
    };
    
    $randomObject = new randomObject;
    $randomObject->alert->setAlertType(new alertRed);
    echo $randomObject->alert->returnAlert($message="Red text for critical info");
    $randomObject->alert->setAlertType(new alertBorderBullet);
    echo $randomObject->alert->returnAlert($message="Border, bullet and pale-color text");
    echo $randomObject->alert->returnAlert($message="Repeat, check style permanence");
    $randomObject->alert->setAlertType(new alertOrangeBgnd);
    echo $randomObject->alert->returnAlert($message="Again, another redefined message style");
    

    randomObject, when initialized (for this case) automatically creates an instance of alertMessanger and makes its methods available. Behaviors can be set and messages echoed. Other alert formats can be created and used when necessary by setAlertType and then returnAlert.

    0 讨论(0)
  • 2021-02-02 14:37

    A couple of important features of the Strategy pattern as envisioned by the Gang of Four are:

    1. It has no conditional statements (so leave out your switch, if, etc conditionals)
    2. It has a Context participant

    Most of the advice on the Strategy leaves out the Context participant. You can find five different examples of the Strategy pattern in PHP here: http://www.php5dp.com/category/design-patterns/strategy/

    0 讨论(0)
提交回复
热议问题