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

时间:2010-02-11 08:48:56

标签: php oop refactoring class-design

基本上我有一个类发送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 ) { }

现在我有基本上支持多个房间的困境,每个房间我必须单独保存每日价格,成人数量的信息,所以我必须对每个房间信息进行会话化,因为它是一个多步骤的形式..

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

编辑#1:在接受建议后,我尝试实现命令模式:

<?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;

3 个答案:

答案 0 :(得分:3)

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

如果您打算以与RoomParsers相同的方式与MultiRoomParser进行交互,则此方案可能是Composite Pattern的良好候选者。基本上,您的MultiRoomParser将包含RoomParsers的集合,当您在MultiRoomParser上调用诸如parse()之类的方法时,它只是遍历其集合中的所有RoomParsers并在每个元素上调用parse()。

答案 1 :(得分:1)

根据问题中的信息,我可能会使用Command Pattern

所有房间都应该实现一个parse()命令

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

请注意,Invoker扩展SplObjectStorage,因此它实现了Countable,Iterator,Traversable,Serializable和ArrayAccess。

答案 2 :(得分:0)

我想说制作对象的多个实例是有道理的。这是对象的工作方式。