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()
折叠到另一个类中并使用该方法。
getFooBarFunction()
迁移到其中。我还需要复制__construct()
($this->
个引用)。MyCustomType
(s)创建一个接口,并将其用于具体类别的替代构造中
的缺点 MyCustomType
进行分组怎么办?
Foo
和Bar
个对象getFooBarFunction()
接受Foo
和Bar
个对象A
,B
,C
实例化并直接使用它
什么是最好的方法(或者#34;最佳实践")以及为什么?还有其他人吗?
A类,B类和C类是一些不会彼此共享任何信息的对象(它们代表Room
,Service
,Supplement
)。唯一的共同特征是每个类都与i18n表有关系(每个类都有自己的表)。所以我的getFooBarFunction()
只是一个用来检索静态类型的函数(存储在某个地方,它并不重要),它表示i18n文本的类型(标题,描述,短名称等)
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()
答案 0 :(得分:2)
回答更新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;
}
}
希望我的想法可以帮助你,快乐的编码!
答案 1 :(得分:0)
我会选择D +接口你的课程。如果getFooBarFunction()
与A,B或C的内部工作无关,并且所有类的实现总是相同的,那么它不应该是这些类的成员。如果调用A,B和C的代码需要知道,那个方法就在那里我会在接口中提取getFooBarFunction()
并在A,B和C中实现。这样,外面的代码可以确定方法永远存在并以工作方式实施。