【问题标题】:Splitting a large PHP class拆分大型 PHP 类
【发布时间】:2016-09-15 06:55:24
【问题描述】:

我有一个大类(1500 行,但很快会是数倍),我想拆分它,以便它更适合SRP(并且每个文件更小,更易于管理。)

该类包含 50-100 个属性,并有几种不同类型的对其执行的操作 - 其中之一是 update,它依次执行多个步骤,例如更新数据库和发送电子邮件。

所以我想我想要 4 节课。

我应该如何构建这些类?


这是我现在所拥有的简化版本:

class Foo {
    public function __construct ($params) {}

    public function update () {
        $this->updateDatabase();
        $this->sendEmails();
    }

    private function updateDatabase () {}
    private function sendEmails () {}
}

$foo = new Foo($params);
$foo->update();

updateDatabase()sendEmails () 都调用了许多其他方法 - 每个都有数百行代码,并且它们有几个同级方法执行其他任务。

使用静态方法的基本重写

class Foo {
    public function __construct ($params) {}
}

class FooUpdate {
    public static function update ($fooParam) {
        FooUpdateDatabase::main($fooParam);
        FooSendEmails::main($fooParam);
    }
}

class FooUpdateDatabase {
    public static function main ($fooParam) {}
}

class FooSendEmails {
    public static function main ($fooParam) {}
}

$foo = new Foo($params);
FooUpdate::update($foo);

使用实例化对象的基本重写

class Foo {
    public function __construct () {}
}

class FooUpdate {
    private $foo;
    public function __construct ($fooParam) {
        $this->foo = $fooParam;
    }
    public function main () {
        $fooTemp = FooUpdateDatabase($this->fooParam);
        $fooTemp->main();
        $fooTemp = FooSendEmails($this->fooParam);
        $fooTemp->main();
    }
}

class FooUpdateDatabase {
    private $foo;
    public function __construct ($fooParam) {
        $this->foo = $fooParam;
    }
    public function main () {}
}

class FooSendEmails {
    private $foo;
    public function __construct ($fooParam) {
        $this->foo = $fooParam;
    }
    public function main () {}
}

$foo = new Foo($bar, ...);
$fooTemp = new FooUpdate($foo);
$fooTemp->update();

或者我应该以某种方式使用继承或特征?

【问题讨论】:

  • 我想你会在Code Review得到最(适当的)反馈。
  • @Marcus 请注意,Foo/Bar 标识符会使其成为不恰当的代码审查问题。
  • @200_success 好点。话虽如此,我认为这个问题是高度基于意见的。
  • @Redzarf - 我建议不要创建诸如 FooSendEmails{} 甚至 FooUpdateDatabase{} 这样的限制性类考虑创建一个可以容纳各种方法的 Email 类执行您的各种操作。这将是您使用 Factory 类来实现多态性的好机会,例如,确定要发送哪种电子邮件(例如 HTML、纯文本、附件等),然后创建附加的 email 类型 i> 实现通用接口的类。那么FooInsertDatabase 呢? FooSelectDatabase?创建单独的类来执行这些操作?
  • @Marcus - 是的,我有单独的类来处理电子邮件的发送和数据库操作。所以FooSendEmails() 做了一些事情,比如构建要插入电子邮件模板的数据的显示版本,并确定电子邮件应该发送给谁——Foo 独有的操作。

标签: php class oop design-patterns single-responsibility-principle


【解决方案1】:

我想发送电子邮件是一回事,代表您的数据是另一回事,而对数据库的读写操作则是第三个。

所以class Fooclass FooPersistenceclass FooMailer
调用FooPersistence::update($foo)也应该调用FooMailer::sendUpdateNotification($foo)

附注:
如果您设置了事件之类的东西,我会在持久性类中触发“更新事件”并为其添加一个发送电子邮件的侦听器。

【讨论】:

【解决方案2】:

正如@SparK 所说,

  • 你的对象 (Foo)
  • 处理数据库通信的类 (FooRepository)
  • 一个发送邮件的类(Mailer)
  • 一个包罗万象的类(FooManager)

    $foo = new Foo($params);
    $fooManager = new FooManager(FooRepository, Mailer);
    $fooManager->update($foo);
    $fooManager->notify($foo); //this could be inside the update or an event.
    

这样您还可以分解您的类(即:分离一个处理数据库连接的类并将其注入 FooRepository 等)。但我不认为有代表动作的类是要走的路吗?

类是可以执行操作的对象(除其他外),而不是操作(这只是一个注释,因为您在示例中使用了名称:p)。

【讨论】:

  • 谢谢,我认为 Manager 类是我需要进一步了解的概念。你能解释一下你的第二行代码吗?或者是$fooRepository = new FooRepository(); $mailer = new Mailer(); $fooManager = new FooManager($fooRepository, $mailer);的简写
  • 是否有任何理由创建FooManager 的实例,而不仅仅是使用静态方法(因为$foo 无论如何都会作为参数传入)。
  • @Redzarf 是的,只是简写。但是您也可以在 FooManager 的构造函数定义中传递接口而不是那些类(即:MailerInterface)。创建它时,您需要传递一个实现该接口的 Mailer 对象。如果您的应用程序正在增长并且其他人正在开发它,这将非常有用。 --- 如果 FooManager 有静态方法,你将如何传递 FooRepository 和 Mailer。您可以在静态函数中创建它们,但我没有看到这样做的原因,也许我错了。另外,如果另一个对象需要使用 FooManager,你可以注入它。
  • @Blitu,然后您可以将FooManager 称为外观。我猜它不会有 notify 方法,因为它会协调管理器(更新方法等)代码中的通知(如果 mailer 不为 null)。
  • @SparK 是的,并且也将其实现为 Singleton。最重要的是降低复杂性,让每个元素都关注其角色而不是其他元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-26
  • 1970-01-01
  • 2011-07-20
  • 1970-01-01
  • 1970-01-01
  • 2017-05-10
相关资源
最近更新 更多