【问题标题】:Is this OOD implemented correctly?此 OOD 是否正确实施?
【发布时间】:2015-10-04 02:31:25
【问题描述】:

我正在学习 OO SOLID 原则和设计模式,我想在上面做一些练习。所以我从我正在进行的项目中得到了一个问题并尝试设计它。请检查它是否正确实施或过度设计或我实施不佳。您的回应是最重要的。

问题 我必须在一个系统中管理短信和电子邮件活动。我的意思是说将它存储在数据库中并检索它等等。

所以我认为会有一些特定于活动的东西,比如创建日期状态等。因此我创建了一个名为活动模型的类,它负责一些与活动相关的常见功能

Class CampaignModel
{
    public function save($data)
    {
        // add campaign specific data
        // save the campaign.

    }

    public function get()
    {
        // select the row from database and return it.

    }
}

然后我制作 smscampaign 和电子邮件活动

class SMSCampaignModel extends CampaignModel
{
    public function save($data)
    {
        // add sms specific data and
        parent::save($data);
    }

    public function gets()
    {
        //fire the query to get the sms campaigns and returns it.
    }
}

class EmailCampaignModel extends CampaignModel
{
    public function save($data)
    {
        // add email  specific data
        parent::save($data);
    }

    public function gets()
    {
        //fire the query to get the email campaigns and returns it.
    }

}

现在每个活动都会有收件人,我们必须存储每个收件人的状态,例如他打开邮件或发送或失败的邮件/短信等。我认为我们将发送带有许多电子邮件或号码的活动,因此我决定创建不同的数据库表用于存储诸如 sms_campaign_log、email_campaign_log 等详细信息。我已经为它创建了接口

interface CampaignLogs
{
    function insert_log();
    function get_details();
}

class SmsCampaignLogs implements CampaignLogs
{
    public function insert_log($data)
    {
        // get the number and status save it into the sms logs table.
    }

    public function get_details($campagin_id)
    {
        // get the logs from campagin table and return it.
    }
}

class EmailCampaignLogs implements CampaignLogs
{
    public function insert_log($data)
    {
        // get the number and status save it into the email logs table.
    }

    public function get_details($campagin_id)
    {
        // get the logs from campagin table and return it.
    }
}

最后我觉得我现在应该使用策略模式来实现它(我不知道它是否正确)。

class Campaign
{
    private $log;
    private $campaign_type;
    public function __construct($campaign, $logger)
    {
        $this->campaign_type = $campaign;
        $this->log  = $logger;
    }

    public function save($data)
    {
        $this->campagin_type->save();

    }
    public function gets()
    {
        $this->campaign_type->gets();
    }

    public function log($data)
    {
        $this->log->insert_log($data);
    }

    public function get_campaign_details($campaign_id)
    {
        $this->log->get_details($campaign_id);
    }
}

现在实现代码。

$campaign = new SmCampaignModel();
$logger = new SmsCampaignLogs();
$c = new Campaign($campagin,$logger);
$c->save($data);
$c->get($campaign_id);
$c->get_campaing_details();

然后我认为是否需要策略模式。 简单来说,我可以实现:

    $campaign = new SmCampaignModel();
    $logger = new SmsCampaignLogs();
    $campaign->save($data);
    $campaign->get($campaign_id);
    $logger->get_campaing_details($campaign_id);

所以我现在完全糊涂了。我想知道我是否在设计中正确应用了 SOLID 原则(以及是否需要/正确使用策略模式)。

【问题讨论】:

  • 那我们可以把这个问题转移到那个网站上还是我想在那里重写这个问题@deceze
  • 这个问题看起来像是实际代码的一个非常精简的“基本”版本。因此,它是“伪”或假设代码,并且 off-topic 用于 codereview.se
  • @Siddhesh 迁移是可能的,但需要主持人干预,并且只有在给出有用的答案/cmets 时才需要。您不妨加快速度并自己在那里发布,然后将其删除。
  • @deceze:停止尝试将问题硬塞到 CR 中。如果这个问题在这里是题外话,那么投票关闭它适当的,列出的原因。您可以建议某个问题可能很适合 CR,但投票结束帖子的第一条规则是它必须在此处实际上是题外话。您正在滥用自定义关闭原因。
  • @deceze:例如,这个问题可能太宽泛了。此时您投票关闭它,建议 OP 它可能更适合 CR(首先检查他们的主题帮助信息)并标记帖子以要求版主迁移它。但不要为此滥用自定义关闭投票消息。

标签: php oop design-patterns solid-principles


【解决方案1】:

在这种情况下,您的 Campaign 类只是一个 Facade。未使用任何策略。

您实际上使用的是 Facades 模式,而不是 Strategy。您的 Campaign 类没有自己的行为。它只是将其行为委托给子系统组件。这不是一件坏事,但它会让你的代码更难维护。在信息隐藏方面很好。

OOD方面没有对错。如果没有提供任何理由,则不必包含设计模式。你应该问自己:“我的主要问题是什么,这能解决它吗?”。 “会不会有理由经常更改代码?”。

因为我们有时都想过度使用设计模式,所以我想向您展示如何建立一个简单的 OO 关系就可以了,甚至更容易阅读和维护。

abstract class Campaign {

    protected $ages;
    protected $countries;
    protected $dailyBudget;

    protected $recipientsStatus = array(); // associative array or a composition of Recipients object

    public function startCampaign()
    {
        // check there is not another run
        $this->executeCampaign();
        $this->collectRecipientsStatus();
        $this->generateStatistics();
    }

    abstract protected function executeCampaign();
    abstract protected function collectRecipientsStatus();
    abstract protected function generateStatistics();

}

class EmailCampaign extends Campaign {

    protected $addresses;

    protected function executeCampaign()
    {
        $this->filterEmailsByCampaignData();
        $this->sendEmails();
    }

    protected function filterEmailsByCampaignData()
    {
        // populate $this->addresses based on ages, countries etc.
    }

    protected function sendEmails()
    {
        // send email to addresses
    }

    protected function collectRecipientsStatus()
    {
        // collect status and fill parent $recipientsStatus
    }

    protected function generateStatistics()
    {
        // generate statistics
    }
}

Campaign 现在是一个包含数据和行为的类。我们不必将其解耦为 Model 和 Logs 等组件。这将工作得很好。但是,如果您发现自己使用了一个更复杂的 Recipients 数组(键值过多或维度数组代码异味),那么您可能会将其解耦到另一组类中。但这应该随着代码的发展而发生。我们根本无法提前预见一切。

顺便说一下,我使用的唯一模式是轻量级的模板方法,以及 OOP 的继承特性。

【讨论】:

  • 但是@techwisdom 先生,您将所有活动功能合并到一个类中,因此 SRP 将被打破。另外,如果我更改电子邮件发送库或其他任何东西它也会打破开放封闭原则吗?我想是的。
  • 先生的代码看起来像是我使用“head first design patterns”鸭示例学到的策略模式。
  • @Siddhesh,首先,外观不是模式的指标。实际上,它们的 OO 结构/UML 有不同的模式相同:State、Strategy、Bridge 和不知何故 Adapter 的实现完全相同。唯一的区别是意图和它们的性质。不是他们如何解决问题,而是为什么。你是对的,SRP 和原子性很重要。但我现在只能看到 Campaign 类仅根据其数据启动活动。这是一个单一的功能。我拆分了 CRUD (db) 操作,因为它不必是类的任务。
  • @Siddhesh,正如我之前写的:没有对错之分。实际上,您编写的代码做得很好。先头是一个好的开始,我可以告诉你做得很好。我的重点是向您展示有时简单会获胜。你展示了一个很好的解决方案,但我唯一的疑问是这个解决方案是否能帮助你解决你在项目中面临的当前需求。但是,如果您只是尝试练习设计模式,请继续这样做。以后您将收集高效的工具来帮助自己。
  • 所以当我们遇到 oo 的问题时,我们应该使用这些模式对吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-25
  • 1970-01-01
  • 2012-06-07
  • 2014-04-15
  • 2011-04-21
  • 2012-09-02
相关资源
最近更新 更多