Стоит ли моделировать объект автомобиля (и его части, например, двигатель) с помощью has-a (состав) или is-a (наследование)?

Я занимаюсь разработкой библиотеки классов, которая будет включать объект Car.

Дилемма заключается в том, что автомобиль будет представлять собой класс с такими полями, как регистрационный номер и другая общая информация об автомобиле.

Но у автомобиля есть двигатель, шасси и т. Д. Эти объекты тоже нужно моделировать. Должны ли они быть классами, встроенными в Car? Если нет, каков сценарий использования встроенного класса?

Я узнал, что композиция является "частью", поэтому вы можете смоделировать отдельные классы и использовать тип двигателя, например, на уровне автомобиля для достижения этой цели. Однако "агрегация", то есть "имеет" отношение с типом, передаваемым в ctor, также применима (у автомобиля "есть" двигатель).

Куда мне идти?

РЕДАКТИРОВАТЬ: Я в настоящее время на домашнее задание, поэтому отсутствие ответа от меня. Библиотека классов предназначена для веб-приложений, основанных на автомобилях. Я профессиональный разработчик (я разрабатываю в.NET для жизни, но как младший), так что это не домашнее задание.

Спасибо

7 ответов

Это действительно зависит от вашего приложения.

Например, вы могли бы реализовать колеса как отдельные классы, содержащие информацию о том, какая шина на нем, как они изношены и т. Д., Но если ваше приложение даже не заботится о колесах, тогда весь класс - пустая трата кода.

Я вижу три варианта использования для композиции:

  • Класс владения стал слишком сложным и должен быть разбит.
  • У класса-владельца есть несколько копий набора свойств, которые могут быть сопоставлены с классом. Это позволяет связать все эти свойства вместе.
  • Содержащийся объект может нуждаться в осмотре или рассмотрении отдельно от объекта, которому он принадлежит (например, вы можете переместить объект Engine на другой автомобиль) или может быть заменен как единое целое.

В итоге: используйте композицию как инструмент для инкапсуляции сложности или устранения повторений. Если он не служит ни одной из этих целей, вероятно, не стоит создавать новый класс.

Класс должен иметь как можно меньше обязанностей, инкапсулировать и делегировать другие функции другим классам. Множество маленьких, простых классов, которые делают что-то одно, являются признаком читаемой, стабильной кодовой базы.

Да, у машины будет "иметь" двигатель, но я бы предложил использовать интерфейс для этого и подобных "имеет" отношения. Опять же, в зависимости от профессора, вы можете получить бонусные баллы за то, что фабрика создала разные машины (подходит, нет?):

public class Car
{
    private Engine engine;
    public Car(Engine engine)
    {
        this.engine = engine;
    }

    public void accelerate()
    {
        this.engine.goFaster();
    }

    public void decelerate()
    {
        this.engine.goSlower();
    }

}

public interface Engine
{
    public void goFaster();
    public void goSlower();
}


public class ReallyFastEngine implements Engine
{
    public void goFaster()
    {
    // some code that goes really fast
    }
    public void goSlower()
    {
    // some code that goes slower
    }    
}

public class NotAsFastEngine implements Engine
{
    public void goFaster()
    {
    // some code that goes not as fast
    }
    public void goSlower()
    {
    // some code that goes slower
    }    
}

public class CarFactory()
{
    public static Car createFastCar()
    {
         return new Car(new ReallyFastEngine());
    }

    public static Car createNotAsFastCar()
    {
         return new Car(new NotAsFastEngine());
    }
}

Видя, что это домашнее задание, и, в зависимости от склонностей вашего наставника / профессора / учителя, вам, вероятно, лучше пойти по пути написания отдельных классов для двигателя, колес и т. Д. Даже при том, что это может быть полностью чрезмерно спроектировано, и ваше приложение может не заботиться о них, возможно, что ваша домашняя работа будет отмечена такими стандартами, как:

"Они определили класс двигателя"

"Есть ли у него разумные методы, такие как Start ()"

"Отметьте их за то, что они смешали все в одном большом классе, что на самом деле проще, потому что они явно не понимают композицию"

Или что угодно, а не те стандарты, которые более прагматичные люди в этой теме применяют к своим собственным проектам.

Разбивайте модель автомобиля только на части, которые будут видны как отдельные объекты за пределами автомобиля. Еще один способ думать об этом - ты действительно понимаешь, как заводится твой автомобиль, когда ты поворачиваешь ключ? Что касается типичного водителя, то все под капотом - это один большой (и шумный) черный ящик. Автоинженеры знают общие детали, которые требуют обслуживания со стороны владельца автомобиля, и специально разработали их для различного уровня взаимодействия с пользователем, таких как щуп для измерения уровня масла или крышка для заправки бачка охлаждающей жидкости.

Можете ли вы моделировать каждый кусок автомобиля? Конечно. Полезно ли моделировать отдельные свечи зажигания? Возможно нет.

Вам нужны машины с разными атрибутами, такими как цвет или размер? Вам нужны автомобили с различными возможностями, такими как пассажирская или буксировочная способность? Одно место, которое отличается, если вам нужны машины с другим поведением. Вот где вам действительно нужно подумать о моделировании объекта Driver, который имеет атрибуты, от простых, таких как время реакции, до сложных, таких как агрессивность.

Моделирование транспортных средств в качестве примеров объектной ориентации или наследования проблематично, потому что примеры на самом деле не объясняют истинных различий между существенными атрибутами, которые определяют класс. Это не новость для Stackru, но этот вопрос также не является дубликатом, см. Эту ветку SO. У меня было то же самое обсуждение с моим другом и разместило журнал этого в моем блоге. Читайте о различных типах воздушных судов, которые FAA признает, и о том, как подразделяются правила для каждого типа. Есть много разных типов самолетов, самое большое разделение между двигателем и без двигателя.

Проверьте определения, используемые FAA:

Воздушное судно означает устройство, которое используется или предназначено для полета в воздухе.

Самолет - самолет с неподвижным крылом с двигателем, более тяжелый, чем воздух, который поддерживается в полете динамической реакцией воздуха на его крылья.

Дирижабль означает летательный аппарат с воздушным двигателем, которым можно управлять.

Существует также легче воздуха и тяжелее воздуха. Воздушный шар не имеет силы и легче воздуха. Дирижабль работает и легче воздуха. Планер не имеет сил и тяжелее воздуха. Боинг 757 оснащен двигателем и тяжелее воздуха, но добавляет еще одну категорию "с неподвижным крылом", которая не похожа на вертолет, который также имеет мощность и тяжелее воздуха, но имеет "вращающееся крыло".

Вот первые четыре в виде таблицы:

                 |  Powered   |    Unpowered
---------------------------------------------------
Lighter-than-air |  Blimp     |    Hot-air balloon 
Heavier-than-air |  737       |    Glider

Вы получаете картину.

Нельзя просто сказать, что вы будете моделировать двигатель отдельно от автомобиля, потому что автомобиль без двигателя может быть совершенно другим животным. Автомобиль без двигателя - не что иное, как трейлер, который также не имеет двигателя, но никогда не будет. В этих случаях ни "есть", ни "имеет" не соответствует конкретному способу построения объектов. Вы не объявляете дирижабль самолетом, который легче воздуха, как воздушный шар. Тот факт, что они оба легче воздуха, никак не связывает их, кроме физики, которой они пользуются. Различие важно, потому что применяемые правила и положения различны. С другой стороны, мы не описываем дирижабль как воздушный шар, у которого есть двигатель. Самолеты физически не связаны, отношения должны быть такими, какими они должны быть.

Если вам не нужно определять ваши объекты с таким уровнем детализации, вам может не понадобиться моделировать их с таким уровнем детализации.

Это зависит от того, что вы пытаетесь сделать. Попытка спроектировать класс "Автомобиль" (или любой другой класс в этом отношении) без представления вариантов использования является бесполезным упражнением.

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

Автомобиль станет объектом высшей иерархии. Включая простые поля, такие как номер, идентификатор или описание. И будет иметь сложные поля, такие как Engine, который сам по себе является объектом.

Так что машина будет выглядеть примерно так:

class Car{
     String ID;
     Engine engine;
}

Это имеет отношение.

По одному критерию вы можете решить, будут ли классы для Engine, Chasis и т. Д.
должен присутствовать как внутренний класс (встроенный класс), является ли экземпляр
эти классы могут быть использованы в другом месте в вашем приложении. В таких случаях
Решение простое, и оно состоит в том, чтобы эти классы существовали отдельно
(не как внутренние классы).

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

Например, если вы создали переменную экземпляра, которая ссылается на
Объект Engine и эта переменная инициализируются в конструкторе Car.And
у вашего класса Engine есть несколько методов, которые нужно протестировать. Тогда как можно
Вы добавляете модульные тесты для проверки кода в классе Engine? Вероятно, вы бы
есть некоторые методы в классе Car, которые показывают поведение или класс Engine, позволяющий
вам написать модульные тесты. Тогда возникает вопрос, есть ли необходимость разоблачить
поведение класса Engine было бы лучше, чем класс Engine
стоит самостоятельно?

В качестве альтернативы, возможно, нет необходимости явно тестировать методы в
Класс двигателя и модульное тестирование методов в Car покрывает код класса двигателя
также. Тогда это отражает тесную интеграцию класса Engine с классом Car.
и будет означать, что он может оставаться как внутренний класс.

Другие вопросы по тегам