PHP思考OOP:发送和接收消息:我是否正确? [英] PHP thinking OOP : sending and receiving Message : am I getting it right?

查看:103
本文介绍了PHP思考OOP:发送和接收消息:我是否正确?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最后查看更新:

当前代码库有1.4k行纯粹的程序代码,它发送短信(有业务)逻辑,数据库连接,一切都在一个巨大的如果条件嵌套了无数的如果 s,没有函数,满是文字,真正的DailyWTF?候选人)。而且我决定咬紧牙关并从头开始重写整个该死的东西。

事情是,这将是我的第一次OOP体验。我尽可能多地阅读关于OOD和良好实践的内容,并决定从简单的事情开始。我想实现消息的发送/接收(主要是文本/短信,但MMS,电子邮件将在未来合并)。所以我写了下面作为我的第一次提交

The current code-base has 1.4k line of purely procedural code which sends sms (has business logic, db connectivity, and everything in one gigantic if conditional nested with countless more ifs, no functions, full of literals, a genuine DailyWTF? candidate). And I have decided to bite the bullet and rewrite the whole damn thing from scratch.
The thing is, this will be my first OOP experience. I read as much as I can about OOD and good practices and decided to start with something simple. I want to implement send/receive of Messages (primarily text/SMS, but MMS, email are to be incorporated in future). So I wrote following as my first commit

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 !!';

我认为我没有正确应用多态的概念。我觉得如果 s不应该在那里,对吧?也许它们对于 setContent()是必要的,但是 sendMessage()呢?所以我想我会将发送部分分成它自己的类SendMessage实现SendMessageInterface 。它将拥有自己的变量 $ server,$ protocol 以及发送电子邮件/文本等的方法。但在写这个课时,我意识到那些如果 s再次爬行为 if($ msg-> getType()=='text')条件。为了补充一点,我正在创建一个新类,它将对象 action 部分分开,这对我来说很困惑(例如 class door 应该负责实现 close() open()方法)。

I don't think I am applying the concept of polymorphism properly. I feel that the ifs shouldn't be there, right? Perhaps they are necessary for setContent() but what about sendMessage() ? So I thought I will separate the sending part into its own class SendMessage implements SendMessageInterface. which will have its own variables for $server, $protocol and methods for sending email/text etc. But while writing that class, I realized those ifs are creeping again as if($msg->getType() == 'text') conditionals. To add to that, I am creating a new class which separates the action part of my object which is confusing to me (e.g. class door should be responsible for implementing close() and open() methods).

现在要么我接受 if s总是在那里(感觉就像打败了多态的整个目的或者我必须做错了

从用户的角度来看,我想象的是:

Now either I accept that the ifs will always be there (which feels like defeating the whole purpose of polymorphism) or I must be doing something wrong.
From a user's perspective, I am imagining something like :

$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(); 调用它?)

what am I missing here? is it impossible to achieve $msg->sendMessage();? Will/should I need different Message classes (MessageEmail,MessageText etc.) ? Should I separate SendMessage (and perhaps have $msg->sendMessage(); call it?)

//这是我甚至没想过接收消息的时候!神救救我 !! :(



2011年8月15日更新:
在考虑了当前代码库的所有方面后,我确定了以下需要实现的部分。

//and this is when I haven't even thought about receiving Message ! God help me !! :(


Update 15th Aug 2011 : After thinking about all the aspects of current code base I have identified following parts which I will need to implement.

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.

我相信我的混淆的主要原因是混合接口与多态性(见评论)您对此有何看法?



2011年8月16日更新

我主要使用接口来强制执行功能。这是'interfaces.php'文件的简短版本

I believe my primary cause of confusion was mixing interfaces with polymorphism(see comment) What is your opinion on it?


Update 16th Aug 2011
I have mainly used interfaces in order to impose functionality. Here is the short version of 'interfaces.php' file

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

类实现很简单(没有花哨的东西,因为我还没有整合类GatewaySMPP将GatewayInterface 实现到我的主消息类中,该类看起来:

class implementations are simple (no fancy stuff, as I am yet to integrate class GatewaySMPP implements GatewayInterface into my main Message class which looks :

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,它涉及大量的套接字操作和响应检查。我只需要在私有函数_send {PDU,SM} 方法周围编写一个包装器公共函数send()

The fun part was to implement GatewaySMPP which involved lot of socket operations and response checking. I just need to write a wrapper public function send() around private function _send{PDU,SM} methods.

当我考虑集成GatewaySMPP时,我意识到我将为每个消息发送操作打开/关闭SMPP连接的套接字。这对于练习/测试来说很好,但在实践中我认为我可能需要更改逻辑以便使用现有连接。 问题是怎么做的?这是当前的逻辑订单:

While I was thinking about integrating GatewaySMPP I realized that I will be opening/closing sockets for SMPP connection for each Message send operation. This is fine for exercise/testing, but in practice I think I may need to change my logic so that existing connection is used. Question is how? Here is current logic in order:

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
    }

Q.我面临的问题是,GatewaySMPP的每个对象都有自己的$ _socket,所以我考虑制作GatewaySMPP单例( shudders )或使用一些全局/状态变量来跟踪套接字以便重用。我想到的一个更好的想法是,如果这些类的使用者使用以下逻辑。 1.为所有 $ objectMessage [] 创建并使用单个 $ objGatewaySMPP 2. objGatewaySMPP- > init(); 3. foreach($ objMessage [] as $ msg)$ msg-> send(); 4. objGatewaySMPP->端(); 。这仍然留下了类的不同用户并发调用的问题?建议/评论请。

Q. The problem I am facing is, each object of GatewaySMPP will have its own $_socket, so I thought about making GatewaySMPP singleton (shudders) or using some global/state variable to keep track of sockets for reuse. A better idea that comes to my mind is if the consumer of these classes uses following logic. 1. Create and use single $objGatewaySMPP for all $objectMessage[] 2. objGatewaySMPP->init(); 3. foreach($objMessage[] as $msg) $msg->send(); 4. objGatewaySMPP->end();. That still leaves the problem of concurrent calls by different users of the class? Suggestions/comments please.

推荐答案

也许尝试这样的事情。这是一个快速尝试,但你应该总是尽量减少代码重复。

Maybe try something like this. This is a quick attempt, but you should always try to minimise code duplication.

<?php

// Message Types

abstract class Message 
{
    private $content; // for email this is the body of the email / for sms it is the 140 characters
    private $sendService;

    public function __construct(SendService $sendService){
        $this->sendService = $sendService;
    }

    public function send($recipient)
    {
        $this->sendService->send($recipient, $this);
    }

}

class EmailMessage extends Message
{
    private $subject;
    private $header;
    //setters and getters / maybe a constructor
}

class SMSMessage extends Message
{
    private $from;
    //setters and getters / maybe a constructor
}


//Services for sending messages

interface SendService
{
    function send(Recipient $recipient, $message);
}

class EmailSendService implements SendService
{
    function send($recipient, EmailMessage $message){
        // you can use only the attributes from the recipient that you need (email address)
        // you can be sure that the message has a header and a subject because you are enforcing
        // the type allowed to be passed to this function
        // do email sending stuff
    }           
}

class SMSSendService implements SendService
{
    function send($recipient, SMSMessage $message){
        // you can use only the attributes from the recipient that you need (tel number)
        // do sms sending stuff
    }           
}

// Defines a 'user' that can be used for both messge types
class Recipient
{
    private $email;
    private $tel;
    private $name;
    //setters and getters
}


// how you would use the above

// 1 - set up recipient - in the real world you would probably have something that would provide this
// to you, like a database lookup
$recipient = new Recipient();
$recipient->setEmail('abc@def.com');
$recipient->setName('Herp Derp');
$recipient->setTel('07770000000000');

// 2 - get a service for sending your message 
$sendService = new SMSSendService();

// 3 - create your message by passing it a service which it can use to send itself
$message = new SMSMessage($sendService);

// 4 - set attributes of your message and then send (passing a recipient to send to)
$message->setContent('lorem ipsum herp derp doop');
$message->send($recipient);

这篇关于PHP思考OOP:发送和接收消息:我是否正确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆