OO:继承与服务

时间:2015-02-11 10:42:39

标签: php oop symfony

Class A
{
  public function __construct(Foo $foo, Bar $bar, MyCustomType1 $mct)
  {
   //...
  }
  //...
  public function getFooBarFunction()
  {
    $this->foo->aMethod();
    $this->bar->anotherMethod();
    //some other execution here
  }
}

Class B
{
  public function __construct(Foo $foo, Bar $bar, MyCustomType2 $mct)
  {
   //...
  }
  //...
  public function getFooBarFunction()
  {
    $this->foo->aMethod();
    $this->bar->anotherMethod();
    //some other execution here (same of Class A)
  }
}

Class C
{
  public function __construct(Foo $foo, Bar $bar, MyCustomType3 $mct)
  {
   //...
  }
  //...
  public function getFooBarFunction()
  {
    $this->foo->aMethod();
    $this->bar->anotherMethod();
    //some other execution here (same of Class B and Class A)
  }
}

正如您所看到的,此代码并不尊重DRY原则。我可以轻松getFooBarFunction()折叠到另一个类中并使用该方法。

<小时/> A)创建一个SuperClass并将getFooBarFunction()迁移到其中。我还需要复制__construct()$this->个引用)。

优点
  - 很容易做到   - 我可以为MyCustomType(s)创建一个接口,并将其用于具体类别的替代构造中 的缺点
  - 如果子类需要在构造阶段添加参数怎么办?   - 如果我不能在同一界面下对MyCustomType进行分组怎么办?
B)创建一个SuperClass并使用setter来&#34;注入&#34; FooBar个对象

优点
  - 太容易了   - 我不需要分享施工人员 的缺点
  - 如果我忘记注入参数怎么办?我是否要在SuperClass中添加额外的显式检查并引发异常?

C)创建一个SuperClass并让getFooBarFunction()接受FooBar个对象

优点
  - 太容易了   - 我不需要分享施工人员 的缺点
  - 在这种情况下,继承真的是必要的吗?
D)创建一个独立的类(服务?)并让ABC实例化并直接使用它


什么是最好的方法(或者#34;最佳实践&#34;)以及为什么?还有其他人吗?

更新

A类,B类和C类是一些不会彼此共享任何信息的对象(它们代表RoomServiceSupplement)。唯一的共同特征是每个类都与i18n表有关系(每个类都有自己的表)。所以我的getFooBarFunction()只是一个用来检索静态类型的函数(存储在某个地方,它并不重要),它表示i18n文本的类型(标题,描述,短名称等)

UPDATE2实际代码

private function getTextTypeNameEntity()
{
    $text_type_repository = $this->getTextTypeRepository();
    $text_type_name_id = $this->container->getParameter('foo_project.text_type.name');
    $text_type_name = $text_type_repository->findOneById($text_type_name_id);

    return $text_type_name;
}

此功能为getFooBarFunction()

2 个答案:

答案 0 :(得分:2)

回答更新2

您说此功能仅通过唯一ID从存储库中提取文本。在不知道完整的课程的情况下,这听起来就像代码气味一堂课应该只做一件事,做得好。当您实现严格相关的功能时,您可以将类扩展为边界。我会将getFooBarFunction更改为仅提供文本ID:

public function getTextId() {
    return 'some-awesome-unique-text-id';
}

原帖

查看您提供的代码时,我只能看到一个区别,MyCustomType。我会输入提示一个共享接口,它为每个可以调用的方法实现签名(接口基础)。这也可以应用于FooBar类。通过使用接口,您可以更轻松地交换实际的类实现。

你说:“如果我不能在同一界面下将自定义类型分组,该怎么办?”这很棘手,是接口的难点之一。将接口视为合同。如果您更改了类的方法签名,但尝试使用它来代替另一个类,则可以确保遇到错误。这将使您的代码更难维护/读取,因为您将尝试处理所有地方的边缘情况。尽量坚持使用界面。

你说:“如果我忘记注入参数怎么办?”首先,这应被视为错误/错误,您作为开发人员负责,抱歉:D

然后你说,“如果我需要在施工期间传递另一个参数怎么办?”。对我而言,听起来像是一个不同的阶级,应该这样对待。然后,如果您还需要其他参数,则可以扩展此类并仅覆盖构造函数。如下所示。

abstract class AbstractImplementation {

    public function __construct(FooInterface $foo, BarInterface $bar, CustomInterface $custom) {

        // Initialize properties.

    }

    /*
     * This could also be declared abstract if each implementation
     * is different.
     */
    public function getFooBarFunction() {

        // Perform basic actions

    }

}

class ActualImplementation extends AbstractExample {

    public function getFooBarFunction() {

        // Perform specific actions

    }

}

然后,如果你需要另一个参数,你可以做。这应该被视为边缘情况。

class ExtendedImplementation extends ActualImplementation {

    public function __construct(Extra $extra, FooInterface $foo, BarInterface $bar, CustomInterface $custom) {

        parent::__construct($foo, $bar, $custom);

        $this->extra = $extra;

    }

}

希望我的想法可以帮助你,快乐的编码!

答案 1 :(得分:0)

我会选择D +接口你的课程。如果getFooBarFunction()与A,B或C的内部工作无关,并且所有类的实现总是相同的,那么它不应该是这些类的成员。如果调用A,B和C的代码需要知道,那个方法就在那里我会在接口中提取getFooBarFunction()并在A,B和C中实现。这样,外面的代码可以确定方法永远存在并以工作方式实施。