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;
}
}
希望我的想法可以帮助你,快乐的编码!