我应该如何重构我的课堂?

问题描述:

基本上我有发送用于房间信息的SOAP请求接收响应的一类,它只能处理一次一个房间..例如:我应该如何重构我的课堂?

class roomParser { 
    private $numRooms; 
    private $adults; 
    private $dailyPrice; 

    public function parse(){} 
    public function send(){} 

}; 

$room = new roomParser($arrival, $departue); 
$return = $room->parse(); 

if ($return) { } 

现在我的基本支持多个房间的窘境,并为每个房间,我不得不单独保留dailyPrice,成年人#的信息,所以我要sessionize每个房间的信息,因为它是一个多步骤的形式..

如果我只是创建我的对象的多个实例,或以某种方式修改我的班级,以便它支持房间数组中的任何房间数,并且在房间数组中它包含每个房间的属性?

编辑#1:服用意见后我试图实现Command模式:

<?php 

interface Parseable { 

    public function parse($arr, $dept); 
} 

class Room implements Parseable { 

    protected $_adults; 
    protected $_kids; 
    protected $_startDate; 
    protected $_endDate; 
    protected $_hotelCode; 
    protected $_sessionNs; 
    protected $_minRate; 
    protected $_maxRate; 
    protected $_groupCode; 
    protected $_rateCode; 
    protected $_promoCode; 
    protected $_confCode; 
    protected $_currency = 'USD'; 
    protected $_soapAction; 
    protected $_soapHeaders; 
    protected $_soapServer; 
    protected $_responseXml; 
    protected $_requestXml; 

    public function __construct($startdate,$enddate,$rooms=1,$adults=2,$kids=0) { 
     $this->setNamespace(SESSION_NAME); 
     $this->verifyDates($startdate, $enddate); 

     $this->_rooms= $rooms; 
     $this->_adults= $adults; 
     $this->_kids= $kids; 

     $this->setSoapAction(); 
     $this->setRates(); 
    } 

    public function parse($arr, $dept) { 
     $this->_price = $arr * $dept * rand(); 
     return $this; 
    } 

    public function setNamespace($namespace) { 
     $this->_sessionNs = $namespace; 
    } 

    private function verifyDates($startdate, $enddate) {} 

    public function setSoapAction($str= 'CheckAvailability') { 
     $this->_soapAction = $str; 
    } 

    public function setRates($rates='') { } 

    private function getSoapHeader() { 
     return '<?xml version="1.0" encoding="utf-8"?> 
      <soap:Header> 
      </soap:Header>'; 
    } 

    private function getSoapFooter() { 
     return '</soap:Envelope>'; 
    } 

    private function getSource() { 
     return '<POS> 
      <Source><RequestorId ID="" ID_Context="" /></Source> 
      </POS>'; 
    } 

    function requestXml() { 
     $this->_requestXml = $this->getSoapHeader(); 
     $this->_requestXml .='<soap:Body></soap:Body>'; 
     return $this->_requestXml; 
    } 

    private function setSoapHeaders ($contentLength) { 
     $this->_soapHeaders = array('POST /url HTTP/1.1', 
      'Host: '.SOAP_HOST, 
      'Content-Type: text/xml; charset=utf-8', 
      'Content-Length: '.$contentLength); 
    } 
} 

class RoomParser extends SplObjectStorage { 

    public function attach(Parseable $obj) { 
     parent::attach($obj); 
    } 

    public function parseRooms($arr, $dept) { 
     for ($this->rewind(); $this->valid(); $this->next()) { 
      $ret = $this->current()->parse($arr, $dept); 
      echo $ret->getPrice(), PHP_EOL; 
     } 
    } 
} 

$arrive = '12/28/2010'; 
$depart = '01/02/2011'; 
$rooms = new RoomParser($arrive, $depart); 
$rooms->attach(new Room('12/28/2010', '01/02/2011')); 
$rooms->attach(new Room('12/29/2010', '01/04/2011')); 
echo $rooms->count(), ' Rooms', PHP_EOL; 

问题中已给出的信息,我可能会使用一个Command Pattern

所有房间应该实现解析()命令

interface Parseable 
{ 
    public function parse($arr, $dept); 
} 

一个房间的情况下可能看起来像这样

class Room implements Parseable 
{ 
    protected $_price; 
    protected $_adults; 
    public function parse($arr, $dept) { 
     // nonsense calculation, exchange with your parse logic 
     $this->_price = $arr * $dept * rand(); 
     return $this; 
    } 
    public function getPrice() 
    { 
     return $this->_price; 
    } 
} 

要通过它们,我会将它们添加到存储所有房间的Invoker中,并知道如何调用其parse()方法,并且也知道如何处理从parse()返回,如有必要

class RoomParser extends SplObjectStorage 
{ 
    // makes sure we only have objects implementing parse() in store  
    public function attach(Parseable $obj) 
    { 
     parent::attach($obj); 
    } 

    // invoking all parse() methods in Rooms 
    public function parseRooms($arr, $dept) 
    { 
     for($this->rewind(); $this->valid(); $this->next()) { 
      $ret = $this->current()->parse($arr, $dept); 
      // do something with $ret 
      echo $ret->getPrice(), PHP_EOL; 
     } 
    } 
    // other methods 
} 

然后你可以使用这样的:

$parser = new RoomParser; 
$parser->attach(new Room); 
$parser->attach(new Room); 
$parser->attach(new Room); 
$parser->attach(new Room); 
echo $parser->count(), ' Rooms', PHP_EOL; 

$parser->parseRooms(1,2); 

注意,祈求延伸SplObjectStorage,所以它实现可数,迭代器,Traversable的,序列化和ArrayAccess接口。

+0

命令模式对于将方法调用方与方法提供程序分开很有用,它允许将方法调用“推迟”,并且还用于撤消方法执行的操作。鉴于OP提供的信息,似乎并不是要求,因此实施这种模式可能是不必要的。这是一个有趣的模式,但:-) – 2010-02-11 17:10:05

+0

@Shakedown是和否命令模式*可以*,但不必提供*撤消*。上述代码与您自己提出的解决方案几乎相同,只是我考虑到OP不需要树。所以我可以争辩说,因为无论如何所有的房间都是叶子,Composite并不是正确的选择,但是我们也可以再次认同它具有Command,Behavior和Composite结构。 – Gordon 2010-02-11 18:11:11

+0

你会在哪里存储适用于所有房间的房产?我的系统工作方式是所有房间必须使用相同的到达/离开日期。目前,我的'Room'类预计前两个参数的到达/离开,我应该只给同一个变量提供'new Room'的所有​​调用,还是让'Room'类从'roomParser'中抓取它? – 2010-02-11 22:44:51

我要说的是,制造对象的多个实例是有道理的。这是对象的工作原理。

那么你所定义的是一个处理单个房间的对象,所以很自然,如果你想处理多个房间,你应该创建一个对象,它只是这些单个房间对象的集合。

如果您打算以与使用RoomParsers相同的方式与MultiRoomParser进行交互,则该场景可能是Composite Pattern的合适人选。基本上,您的MultiRoomParser将包含一个RoomParsers集合,并且当您在MultiRoomParser上调用诸如parse()之类的方法时,它将遍历集合中的所有RoomParsers,并在每个元素上调用parse()。

+0

原谅我没有提到这一点,但如果我必须存储所有房间的通用信息,例如货币和要使用的SOAP URI,那么MultiRoomParser会继续吗? – 2010-02-11 20:34:24

+0

这些信息可能在MultiRoomParser中,但请记住,一旦将货币和SOAP信息放入MultiRoomParser中,MultiRoomParser变得不那么一般和更具体,因此重用可能会更困难,或者您可以使用的情况它会更有限。 也许你可以创建另一个包含货币和SOAP信息以及MultiRoomParser的类。 – 2010-02-11 21:05:31