我应该如何重构我的课堂?
基本上我有发送用于房间信息的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接口。
我要说的是,制造对象的多个实例是有道理的。这是对象的工作原理。
那么你所定义的是一个处理单个房间的对象,所以很自然,如果你想处理多个房间,你应该创建一个对象,它只是这些单个房间对象的集合。
如果您打算以与使用RoomParsers相同的方式与MultiRoomParser进行交互,则该场景可能是Composite Pattern的合适人选。基本上,您的MultiRoomParser将包含一个RoomParsers集合,并且当您在MultiRoomParser上调用诸如parse()之类的方法时,它将遍历集合中的所有RoomParsers,并在每个元素上调用parse()。
原谅我没有提到这一点,但如果我必须存储所有房间的通用信息,例如货币和要使用的SOAP URI,那么MultiRoomParser会继续吗? – 2010-02-11 20:34:24
这些信息可能在MultiRoomParser中,但请记住,一旦将货币和SOAP信息放入MultiRoomParser中,MultiRoomParser变得不那么一般和更具体,因此重用可能会更困难,或者您可以使用的情况它会更有限。 也许你可以创建另一个包含货币和SOAP信息以及MultiRoomParser的类。 – 2010-02-11 21:05:31
命令模式对于将方法调用方与方法提供程序分开很有用,它允许将方法调用“推迟”,并且还用于撤消方法执行的操作。鉴于OP提供的信息,似乎并不是要求,因此实施这种模式可能是不必要的。这是一个有趣的模式,但:-) – 2010-02-11 17:10:05
@Shakedown是和否命令模式*可以*,但不必提供*撤消*。上述代码与您自己提出的解决方案几乎相同,只是我考虑到OP不需要树。所以我可以争辩说,因为无论如何所有的房间都是叶子,Composite并不是正确的选择,但是我们也可以再次认同它具有Command,Behavior和Composite结构。 – Gordon 2010-02-11 18:11:11
你会在哪里存储适用于所有房间的房产?我的系统工作方式是所有房间必须使用相同的到达/离开日期。目前,我的'Room'类预计前两个参数的到达/离开,我应该只给同一个变量提供'new Room'的所有调用,还是让'Room'类从'roomParser'中抓取它? – 2010-02-11 22:44:51