Черты против абстрактных классов для повторного использования кода

Работая над проектом, я наткнулся на вопрос, касающийся правильного выбора правильной формы повторного использования кода с точки зрения характеристик и абстрактных базовых классов. Я столкнулся с тем, что у меня есть несколько абстрактных базовых классов, но я могу наследовать только от одного из-за множественных ограничений наследования от PHP. Переосмысление этого заставляет меня подвергать сомнению мой дизайн, и поэтому я хочу знать, как другие решат эту проблему.

Следующий сценарий

В моем проекте у меня есть два вида расчетов

  1. Простые расчеты
  2. Сгруппированные вычисления, которые в случае являются простыми вычислениями просто с дополнительной информацией

Настройка интерфейсов

interface SimpleResultInterface{
public function getValue();
}

interface GroupedResultInterface extends SimpleResultInterface {
public function getGroupValues();
}

Настройка базовых классов

Чтобы избежать дублирования кода как хорошей формы дизайна, я создал два абстрактных базовых класса.

abstract class SimpleResultBase implements SimpleResultInterface{

public function getValue(){
return 1;
}
}

abstract class GroupedResultBase extends SimpleResultBase implements  GroupedResultInterface {

public function getGroupValues(){
return array(
"group1" => 1,
"group2" => 2,
"group3" => 3,
);
}
}

Итак, первый вопрос здесь

  1. Есть ли GroupedResultBase нужно наследовать SimpleResultBase с точки зрения выражения отношения интерфейса от SimpleResultInterface а также GroupedResultInterface ?

Я выбрал да, потому что в противном случае мне пришлось бы дублировать ПолучитьЗначение метод из SimpleResultBase

Что у нас пока

Теперь я могу выразить

  1. GroupedResultInterface экземпляр SimpleResultInterface ( правда )
  2. GroupedResultBase экземпляр SimpleResultBase ( правда )
  3. SimpleResultBase экземпляр SimpleResultInterface ( правда )
  4. GroupedResultBase экземпляр GroupedResultInterface ( правда )

Достигать конкретных целей там, где начинаются неприятности

На данный момент нет конкретных классов. Теперь я хочу сделать два конкретных класса, которые имеют отношения вместе, соблюдая определения интерфейса.

class OEESimpleResult extends SimpleResultBase {

}

class OEEGroupedResult extends GroupedResultBase{

}

это работает очень хорошо, но то, что я не могу сделать, это

class OEESimpleResult extends SimpleResultBase {

}

class OEEGroupedResult extends OEESimpleResult,GroupedResultBase {

}

Интерфейс GroupedResultInterface расширяет SimpleResultInterface

Как указано выше, в определении интерфейса. Каждый сгруппированный результат также
простой результат. Так что я бы ожидал, что OEEGroupedResult также является OEESimpleResult

Но когда я это сделаю, я не смогу повторно использовать свой абстрактный базовый класс GroupedResultBase потому что множественное наследование не допускается. Это приводит меня к следующим вопросам.

  1. Кажется, что классовые отношения в абстрактных классах замораживают цепочку наследования. Было бы лучше удалить абстрактные классы и заменить их на черты, делающие их конкретными классами?
  2. Как правильно предоставить реализации по умолчанию, если у вас есть несколько интерфейсов, но они могут наследовать только от одного базового класса?
  3. Эта проблема кажется очень распространенной в oop, так что есть ли лучшие практики и рекомендации, как преодолеть эту проблему?
  4. Должны ли классы, которые реализуют интерфейсы, также выражать отношения в форме наследования, как на уровне интерфейса, или достаточно только реализации интерфейса? В моем случае следует OEEGroupedResult выразить отношение к OEESimpleResult на уровне класса, как их интерфейсы на уровне интерфейса.

Спасибо за вашу помощь 🙂

1

Решение

Поскольку вы работаете в стиле oop, вы можете услышать о принципах SOLID.
Таким образом, ваш дизайн разбивает следующие буквы S, I, D с возможностью разбить O и L.

Так как ты сломал «S»:
Прямо здесь!

class OEEGroupedResult extends OEESimpleResult,GroupedResultBase {

}

Внезапно или к счастью php не допустит этого, но ваш класс предоставит некоторую дополнительную отдельную логику, поэтому у вас будет по крайней мере две причины, чтобы изменить это. Но да, это из-за

interface GroupedResultInterface extends SimpleResultInterface {
public function getGroupValues();
}

Вот твой я перерывы Решение довольно простое: подумайте о методах, которые действительно нужны вашему GroupedResultInterface, и поместите его внутрь и действительно означает, что эти методы должны выполнять одну и ту же работу. Они не так, как вы нарушаете письмо D Вот:

abstract class SimpleResultBase implements SimpleResultInterface{

public function getValue(){
return 1;
}
}

abstract class GroupedResultBase extends SimpleResultBase implements  GroupedResultInterface {

public function getGroupValues(){
return array(
"group1" => 1,
"group2" => 2,
"group3" => 3,
);
}
}

Твой класс class GroupedResultBase зависит от конкретного метода другого класса. Но вы быстро исправите это после разделения интерфейса.

уведомление. Я использую черты, когда я не могу что-то изменить внутри классов вендоров. Только. Это только я, но когда я думаю, что эта черта поможет мне, тогда что-то не так с архитектурой. Это зависит от вас, конечно.

Маленькая ссылка: https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

Повеселись!

1

Другие решения

Других решений пока нет …