См. Обновления в конце:
Текущая кодовая база имеет 1,4 тыс. Строк чисто процедурного кода, который отправляет SMS-сообщения (имеет бизнес-логику, подключение к БД и все в одном гигантскомif
условно вложено с бесчисленным количеством if
с, без функций, полным литералов, подлинным кандидатом DailyWTF?).И я решил укусить пулю и переписать всю эту чертову штуку с нуля.
Дело в том, что это будет мой первый опыт ООП.Я прочитал как можно больше об ООД и передовой практике и решил начать с чего-то простого.Я хочу реализовать отправку / получение сообщений (в первую очередь текстовых / SMS, но MMS, электронная почта должны быть включены в будущем).Поэтому я написал следующее как мой первый коммит
interface MessageInterface {
public function setType($type); public function getType();
public function setContent($content); public function getContent();
public function sendMessage(); //add more functionalities later
}
class Message implements MessageInterface {
private $_type; private $_content;
public function setType($type) { $this->_type = $type; }
public function getType() { return $this->_type; }
public function setContent($content) {
if ($this->_type = 'text') {
$this->_content = $content;
return TRUE; // report success
} else { return FALSE; } // report failure
}
public function getContent() { return $this->_content; }
public function sendMessage() {
if ($this->_type == 'text') {
print "Sending ".$this->getContent()." as ".$this->getType()." message\n";
//do the actual implementation later
return TRUE; // report success
} else { return FALSE; } // report failure
}
}
$msg = new Message();
$msg->setType('text');
print $msg->getType() . "\n"; //text
$result = $msg->setContent('Hello World!');
if($result)
$result2 = $msg->sendMessage(); //Sending Hello World! as text message
if($result2)
print 'Hurray ! Mission accomplished !!';
Я не думаю, что правильно применяю концепцию полиморфизма.Я чувствую, что if
не должно быть там, верно?Возможно, они необходимы для setContent()
, но как насчет sendMessage()
?Поэтому я решил разделить отправляющую часть на свою собственную class SendMessage implements SendMessageInterface
.который будет иметь свои собственные переменные для $server, $protocol
и методы для отправки электронной почты / текста и т. д. Но во время написания этого класса я понял, что эти if
s снова подкрадываются как if($msg->getType() == 'text')
условные выражения.Чтобы добавить к этому, я создаю новый класс, который отделяет action часть моего объекта , что меня смущает (например, class door
должен отвечать за реализацию close()
иopen()
методы).
Теперь либо я принимаю, что if
всегда будут там (что похоже на поражение всей цели полиморфизма), либо я должен что-то делать неправильно .
Отс точки зрения пользователя, я представляю что-то вроде:
$msg = new Message();
$msg->setType('email'); //or 'text' or 'mms' etc.
$msg->setContent($content); //e.g. $content=array('subject'=>'foo','body'=>'bar')
$msg->sendMessage();
//if the last line is not possible, then perhaps
//$sender = new SendMessage($msg);
//$sender->send();
что мне здесь не хватает?нельзя ли достичь $msg->sendMessage();
?Будут ли / мне нужны различные сообщения классов (MessageEmail
, MessageText
и т. Д.)?Должен ли я отделить SendMessage
(и, может быть, $msg->sendMessage();
позвонить?)
// и это когда я даже не думал о получении сообщения !Боже, помоги мне !!:(Обновление от 15 августа 2011 года. Подумав обо всех аспектах текущей кодовой базы, я определил следующие части, которые мне нужно будет реализовать.
a. Message Class(es) (type, content, sender, receiver, DateTime of send/receive etc.)
Responsibilities:
creating and modifying messages
ascribing consistent and appropriate characteristics of a message
b. Send Class(es) (protocol, header info, server/operator to use)
Responsibilities:
Sending messages
Changing the state of Message (for setting send DateTime of Message)
e. Database Class(es) (id, content, to, from, time etc.)
Responsibilities:
Represent Message for storage.
CRUD (Create, Read, Update, Delete) actions on this representation for DBMS.
e. Interfaces (MAX_MESSAGE_LENGTH, TIMEOUT etc. )
Responsibilities:
Provide interface for communication between various modules.
Я считаю, что моей основной причиной путаницы было смешивание интерфейсов с полиморфизмом ( см. Комментарий ) Что вы думаете об этом?Обновление от 16 августа 2011 года
В основном я использовал интерфейсы для наложения функциональности.Вот краткая версия файла 'interfaces.php'
interface MessageInterface {
//omitting getters for clarity
public function setType($type);
public function setSender(IdentityInterface $sender);
public function setReceiver(IdentityInterface $receiver);
public function setSendGateway(GatewayInterface $sendGateway);
}
interface IdentityInterface {
public function setName($name);
public function setAddress($address);
}
interface GatewayInterface {
public function setProtocol($protocol);
public function send(IdentityInterface $sender, IdentityInterface $receiver, ContentInterface $content);
}
. Реализации класса просты (ничего особенного, так как я еще не включил class GatewaySMPP implements GatewayInterface
в мой основной класс Message
, который выглядит так:
class Message implements MessageInterface {
private $_type; private $_content;
private $_sender; private $_receiver;
private $_sendGateway; //private $_receiveGateway; private $_dataStorage;
public function __construct(
$type = NULL, $content = NULL,
IdentityInterface $sender = NULL,
IdentityInterface $receiver = NULL,
GatewayInterface $sendGateway = NULL
) {
$this->setType($type); $this->setContent($content);
($sender === NULL)
? $this->setSender(new Identity())
: $this->setSender($sender);
($receiver === NULL)
? $this->setReceiver(new Identity())
: $this->setReceiver($receiver); //similarly for $setSendGateway etc.
}
//setters and getters, omitting for clarity
public function send(...) { //testing pending
$this->_sendGateway->send($this->getSender(), $this->getReceiver(), $this->getContent ...)
}
Самое интересное было реализовать GatewaySMPP, который включал множество операций с сокетами и проверку ответов. Мне просто нужно написать оболочку public function send()
для private function _send{PDU,SM}
методов.
Пока я былРазмышляя об интеграции GatewaySMPP, я понял, что буду открывать / закрывать сокеты для соединения SMPP для каждой операции отправки сообщения. Это хорошо для упражнения / тестирования, но на практике я думаю, что мне может понадобиться изменить свою логику так, чтобы существующее соединение Вопрос в том, как? Вот текущая логика в следующем порядке:
class GatewaySMPP {
private $_socket,$_port,$_host //etc.
public function __construct($host,$port,$user,$passwd) {
$this->_socket = FALSE;
$this->_host = $host; //initialize other private variables
}
public function init() {
if($this->_socket !== FALSE) return FALSE; //socket already in use
$this->_socket = fsockopen($this->_host, $this->_port ...)
//prepare bind statement for initiating SMPP connection and fwrite to socket
$this->_sendPDU(BIND, $data)
}
public function send($receiver, $sender, $message, ...) {
//use private functions which do actual socket operations
$this->_sendSM($receiver, $sender, $message, ...)
}
public function end() {
if($this->_socket === FALSE) return; //socket already closed
this->_sendPDU(UNBIND, ''); //omitting response check
$result = fclose($this->_socket); //omitting response check
}
В. Проблема, с которой я сталкиваюсь, заключается в том, что каждый объект GatewaySMPP будет иметь свой собственный $_socket, поэтому я подумал о создании одиночного шлюза GatewaySMPP ( shudders ) или использовании некоторой глобальной переменной / состояния для отслеживания сокетов для повторного использования.Идея, которая приходит мне в голову, заключается в том, что потребитель этих классов использует следующую логику.1. Создайте и используйте один $objGatewaySMPP
для всех $objectMessage[]
2. objGatewaySMPP->init();
3. foreach($objMessage[] as $msg) $msg->send();
4. objGatewaySMPP->end();
.Это все еще оставляет проблему одновременных звонков разными пользователями класса?Предложения / комментарии, пожалуйста.