php - Setting the strategy in a Strategy Pattern -


i might have implementing wrong cannot figure out solid way of setting strategy use in implementation of strategy pattern. i'm not big fan of writing "statically", perhaps there way.

backstory: i've done 2 (2) implementations (soap + http) shipping providers in order retrieve track & trace information whatever user inputs frontend. each follow interface know functions , should (php :3) available. i've shortened class names below magento , class names long.

flow: customer inputs tracking number in form , submits. request sent controller, controller initializes instance of service class, sets output via. $service->setoutput('tracking/service_gls') - note tracking/service_gls maps directly service class (magento thing), $service->getdeliveryinformation($number) called (we know exists because of interface), entire $service object returned view , data presented.

my challenge: i'm using switch case set tracking/service_gls , tracking/service_otherservice calling getdeliveryinformation(). correct approach? feel it's bit static , hard maintain if wants connect shipping provider. have enter controller , manually add entry switch case, in function somewhere 200 lines deep in class.

example of how controller looks:

public function getdeliveryinformationaction() {     $id = $this->getrequest()->getparam('id', false);     if ($id && $this->getrequest()->isajax())     {         // note: service parameter 2 radio buttons values "gls", "otherservice"         $servicetype = $this->getrequest()->getparam('service', false);          try         {             // note: same doing new class()             $service = mage::getmodel('tracking/service');              switch ($servicetype)             {                 case 'gls':                 $service->setoutput('tracking/service_gls');                 break;                  case 'other':                 $service->setoutput('tracking/service_other');                 break;             }              $shipment = $service->getdeliveryinformation($id);              $output = // .. create block contains view, $output contain shipment data; returned ajax request.         }         catch (exception_requesterror $e)         {             ..         }          //         $this->getresponse()->setheader('content-type', 'text/html', true);         $this->getresponse()->setbody($output);     } } 

code has been shortened bit there lots more functions, not important.

interface 2 shipping provider models implementing

interface output {     /* requests delivery information specified tracking number */     public function getdeliveryinformation($number);      /**     * returns acceptor name     * @return string     */     public function getacceptorname(); } 

service class handles requesting data shipping models

class service {     protected $output;       /**      * sets output model use      * @param string $outputtype      */     public function setoutput($outputmodel)     {         // note: same doing new class()         // magento people note: getmodel() works fine tho.. ;-)         $modelinstance = mage::app()->getconfig()->getmodelinstance($outputmodel);         $this->output = $modelinstance;     }      /**      * returns delivery information specified tracking number      * @param string $number      * @return instance of output class      */     public function getdeliveryinformation($number)     {         // note: makes shipping class request         // information , set data internally on object         $this->output->getdeliveryinformation($number);         return $this->output;     } } 

example of shipping class; have 2 in case

class service_gls implements output {     const service_name = 'gls';     const service_url = 'http://www.gls-group.eu/276-i-portal-webservice/services/tracking/wsdl/tracking.wsdl';      protected $locale = 'da_dk';       /* class constructor */     public function __construct() { }      /**      * requests delivery information specified tracking number      * @param mixed $number      */     public function getdeliveryinformation($number)     {         $this->_getdeliveryinformation($number);     }      /**      * requests , sets information specified tracking number      * @param mixed $number      */     private function _getdeliveryinformation($number)     {         // note: extending varien_object has magic __get, __set .. hence why there no getdata() function in class.         if (!count($this->getdata()))         {             $client = new soapclient($url);             $client->gettudetail($reference));              .. set data         }     }      /**      * returns acceptor name      * @return string      */     public function getacceptorname()     {         $signature = $this->getsignature();         return (isset($signature)) ? $this->getsignature() : false;     }      /**      * returns name of current service      * @return string      */     public function __tostring()     {         return self::service_name;     } } 

controller

class ajaxcontroller extends mage_core_controller_front_action {     public function getdeliveryinformationaction()     {         $id = $this->getrequest()->getparam('id', false);         if ($id && $this->getrequest()->isajax())         {             // note: service parameter 2 radio buttons values "gls", "otherservice"             $servicetype = $this->getrequest()->getparam('service', false);             try             {                 $service = mage::getmodel('tracking/service');                  switch ($servicetype)                 {                     case 'gls':                     $service->setoutput('tracking/service_gls');                     break;                      case 'other':                     $service->setoutput('tracking/service_other');                     break;                 }                  $shipment = $service->getdeliveryinformation($id);                  $output = // .. create block contains view, $output contain shipment data; returned ajax request.             }             catch (exception_requesterror $e)             {                 ..             }              //             $this->getresponse()->setheader('content-type', 'text/html', true);             $this->getresponse()->setbody($output);         }     } } 

well either switch or sort of string concatenation return strategy class need.

with strategy pattern, choosing correct strategy @ run time done through strategycontext pattern: https://sourcemaking.com/design_patterns/strategy/php . allows isolate algorithm choose correct strategy not "in function somewhere 200 lines deep in class." .

as algorithm setting runtime strategy, fan of class constants rather string manipulation etc. since aim of game arrive @ class name instantiate, why not class constant return class name.

class outputstrategycontext{     const service = 'tracking/service_gls';     const other = 'tracking/service_other';      private $strategy;      public function __construct($servicetype)     {         $strategy = constant('self::' . strtoupper($servicetype));         $modelinstance = mage::app()->getconfig()->getmodelinstance($strategy);         $this->strategy = $modelinstance;     }      public function getstrategy()     {         return $this->strategy;     } } 

lightweight , easy maintain, list of strategy classes in 1 place.

you can of course make whole thing static, or use design pattern abstract factory method acheive same thing. really.

anyway in controller one-liner

class ajaxcontroller extends mage_core_controller_front_action {     public function getdeliveryinformationaction()     {         $id = $this->getrequest()->getparam('id', false);         if ($id && $this->getrequest()->isajax())         {             // note: service parameter 2 radio buttons values "gls", "otherservice"             $servicetype = $this->getrequest()->getparam('service', false);             try             {                 $service = mage::getmodel('tracking/service');                 $outputmodel = new outputstrategycontext($servicetype)->getstrategy();                 $service->setoutput($outputmodel);                  $shipment = $service->getdeliveryinformation($id);                  $output = // .. create block contains view, $output contain shipment data; returned ajax request.             }             catch (exception_requesterror $e)             {                 ..             }              //             $this->getresponse()->setheader('content-type', 'text/html', true);             $this->getresponse()->setbody($output);         }     } } 

of course have modify service . modified context class code.

class service {     protected $output;       /**      * sets output model use      * @param string $outputtype      */     public function setoutput($outputmodel)     {         // note: same doing new class()         // magento people note: getmodel() works fine tho.. ;-)         $this->output = $outputmodel;     }      /**      * returns delivery information specified tracking number      * @param string $number      * @return instance of output class      */     public function getdeliveryinformation($number)     {         // note: makes shipping class request         // information , set data internally on object         $this->output->getdeliveryinformation($number);         return $this->output;     } } 

Comments

Popular posts from this blog

asp.net mvc - SSO between MVCForum and Umbraco7 -

Python Tkinter keyboard using bind -

ubuntu - Selenium Node Not Connecting to Hub, Not Opening Port -