php – OO:继承与服务

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-> references).
优点
  – 很容易做到
  – 我可以为MyCustomType创建一个接口,并将其用于具体类的替换中的构造
缺点
  – 如果子类需要在构造阶段添加参数怎么办?
  – 如果我不能在同一个界面下分组MyCustomType怎么办?

B)创建一个SuperClass并使用setter来“注入”Foo和Bar对象
优点
  – 也很容易
  – 我不需要共享构造函数
缺点
  – 如果我忘记注入参数怎么办?我是否要在SuperClass中添加额外的显式检查并引发异常?

C)创建一个SuperClass并让getFooBarFunction()接受Foo和Bar对象
优点
  – 也很容易
  – 我不需要共享构造函数
缺点
  – 在这种情况下,继承真的是必要的吗?

D)创建一个独立的类(服务?),让A,B,C实例化它并直接使用它

什么是最好的方法(或“最佳实践”),为什么?还有其他人吗?

UPDATE

A类,B类和C类是一些不共享任何信息的对象(它们代表房间,服务,补充).唯一的共同特征是每个类都与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

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

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

原帖

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

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

你说:“如果我忘记注入参数怎么办?”首先,这应该被认为是一个错误/错误,你作为开发人员负责,抱歉: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;

    }

}

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

点赞