2012-02-14 4 views
5

Предположим, у меня есть объект, автомобиль, и у него есть наборы методов, которые ... несопоставимы? Может быть, похож на Блоб? (как в antipattern, «blob»). Эти методы работают в достаточно разных наборах и на самом деле не пересекаются функционально.Где идут новые методы?

Car 
# methods related to suburban driving 
    ->foo1 
    ->foo2 
# methods related city driving 
    ->bar3 
    ->bar4 

Теперь давайте говорить, что я хотел бы добавить «внедорожное вождение» в качестве одного из случаев, которые могут поддержать мой объект автомобиля. Если я добавляю методы к объекту Car, разве это не делает его более похожим на blob?

Car (augmented) 
# methods related to suburban driving 
    ->foo1 
    ->foo2 
# methods related city driving 
    ->bar3 
    ->bar4 
# methods related off road driving 
    ->blah5 
    ->blah6 

Должен ли я:

A: Подкласс автомобилей. Я могу сделать объект OffRoadCar extends Car. Но что, если Car и OffRoadCar используют одни и те же данные/состояние и отличаются только методами? OffRoadCar только «действует» более конкретно, чем автомобиль, но больше не описывается и не имеет уникальных полей. Поэтому создание экземпляра OffRoadCar бессмысленно.

OffRoadCar extends Car 
# methods related off road driving 
    ->blah5 
    ->blah6 

Б: Потребляйте автомобиль с статическим методом. Как OffRoadAdventure-> Embark (Car). Таким образом, класс OffRoadAdventure принимает объект Car и имеет свой путь.

В C# это будет называться методом расширения.

Я думаю, что есть другой способ: Каково решение Blap antipattern? Это подклассы? Это методы расширения?

Кроме того, еще одна причина, по которой я хотел использовать эти методы, заключается в том, что если их реализация несет определенную стоимость, например, включение других классов/пакетов? Я бы не хотел, чтобы пользователи основного класса постоянно платили за то, что они никогда не использовали. Я полагаю, что стоимость, выделяемая для меньшинства, стоит экономии большинства. И это делает граф зависимостей более точным (и не похожим на blob-like).

PS - Язык реализации Perl.

+0

Автомобиль должен быть классом? Может ли автомобиль действительно быть ICar (интерфейс)? Я бы предложил маршрут композиции над наследованием. – OnResolve

+0

Автомобиль уже настоящий класс, который используется. (это фактически артефакт ORM) –

ответ

0

Я думаю, что вы на правильном пути. Изящное решение состоит в том, чтобы унаследовать OffRoadCar от Car и переопределить его метод Drive(). Таким образом, вы можете сказать:

Car myCar = new OffRoadCar(); 
myCar.Drive(); 

Это будет вызывать преодолено Drive() метод в подклассе, и вы не в конечном итоге с методами Gazillion в одном «сгустка». Вот как метод Drive() в OffRoadCar может выглядеть следующим образом:

@Override 
public void Drive() 
{ 
/* code */ 
} 
2

С Perl вы должны принимать хороший взгляд на лося и роли.

package Suburban; 
use Moose::Role; 

requires 'wheels'; 

sub 'foo1' { 
    ... 
} 


sub 'foo2' { 
    ... 
} 

package City; 
use Moose::Role; 

requires 'wheels'; 

sub 'bar3' { 
    ... 
} 


sub 'bar4' { 
    ... 
} 

package Offroad; 
use Moose::Role; 

requires 'wheels'; 

sub 'blah5' { 
    ... 
} 


sub 'blah6' { 
    ... 
} 

package UltraCar; 
use Moose; 

with qw/ Offroad City Suburban /; 
has 'wheels' => (is => 'rw', isa => 'Int', default => 4); 

package RentalCar; 
use Moose; 

with qw/ City Suburban /; 
has 'wheels' => (is => 'rw', isa => 'Int', default => 4); 

package Tricycle; 
use Moose; 

with qw/ Offroad /; 
has 'wheels' => (is => 'rw', isa => 'Int', default => 3); 

Вы даже можете добавлять и удалять роли во время выполнения.

+1

Как это касается проблемы с блобом? Роль/интерфейс для разрозненных классов, выполняющих один и тот же контракт. –

+1

Проблема с блобом заключается в том, что вы перемещаете все функциональные возможности объекта в одно место. Использование ролей позволяет разбить разрозненные функции на отдельные, тестируемые модули кода, а затем применить их к вашим объектам по мере необходимости. Во время выполнения, да, у вас все еще есть «объект божественного бога», но в этот момент вас это действительно не беспокоит, потому что проблемы с этим антипаттерном - это перестройка. Поскольку вы можете применять роли во время выполнения, вы можете также добавить крен только те функции, в которых вы нуждаетесь, и не использовать ненужные хиты производительности. – Oesor

+0

Ваши изменения сделали это более понятным. Но по некоторым техническим ограничениям мы не можем использовать Moose. Я понимаю, что вы говорите. –

0

Вместо подкласса класса Car вы можете использовать какую-либо форму Decorator pattern.

Здесь базовый класс ORM и декораторы (скажем OffRoadDecorator) реализуют некоторый общий интерфейс, и поведение каждого декоратора может быть динамически добавлено в исходный класс.

Главное отличие здесь в том, что несколько декораторов могут использоваться на одном и том же классе Car, и это зависит от вашей реализации, чтобы сказать, как они должны взаимодействовать. Вам нечего прекращать украшать ваш класс, используя OffRoadDecorator, а также SuburbanDecorator, и вы можете точно определить, что это означает для автомобиля в декораторах.

(PS жаль, что я не даю никаких примеров коды, мой Perl просто страшно Посмотрите this page для некоторых других примеров.).

0

Не совсем ответ Марк и я не знаю, как глубоко вы хотите вникать в это, но вы могли бы задуматься над идеей Order Resolution. Вместо стандартного поиска глубины поиска, используя mro, вы можете выполнить поиск по ширине. См. this page на CPAN и brian d foy в статье Use the C3 method resolution order in multiple inheritance для получения дополнительной информации.

0

Пригородные, городские и внедорожные Вождения звучат как алгоритмы. Шаблон стратегии может помочь здесь, когда Context является Car.

Смежные вопросы