Главная » Разработка для Android » Модульное программирование в Java ДЛЯ ANDROID

0

Несомненно, возможность расширения классов в Java обеспечивает разработчикам существенную гибкость при переопределении различных аспектов объектов, в зависимости от того, в каком контексте объект используется. Однако требуется немалый практический опыт, чтобы научиться рационально использовать классы и интерфейсы. В идеале разработчик стремится создавать такие фрагменты кода, в которые будет несложно вносить изменения с течением времени и которые можно будет многократно использовать в максимально разнообразных контекстах, в многочисленных приложениях и, возможно, даже в качестве библиотек. При применении такого подхода к программированию удается значительно снизить количество ошибок и время, необходимое для вывода приложения на рынок. Модульное программирование, инкапсуляция и разделение функций – основные стратегии, обеспечивающие стабильность кода и пригодность его к многократному использованию.

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

Разработчик начинает с создания класса транспортных средств, в котором содержится вся транспортная логика и вся логика для конкретного типа двигателя, вот так:

Это упрощенный код. Он, возможно, и будет работать, но в нем перемешаны не связанные друг с другом типы реализации (например, все типы двигателей). Поэтому код будет сложно расширять. Рассмотрим, например, случай, в котором требуется изменить реализацию и добавить в нее новый тип двигателя (ядерный). Код для каждой разновидности автомобильного двигателя имеет неограниченный доступ к коду любого другого двигателя. Ошибка в реализации двигателя может спровоцировать ошибку в совсем другом двигателе. Изменение одного двигателя может привести к неожиданным изменениям в другом. И, конечно же, машине, в которой нет электрического двигателя, придется тем не менее тащить с собой представления всех существующих в системе типов двигателей. Разработчики, которым в перспективе придется реализовать для этой программы монолитный двигатель, должны понимать все сложные взаимодействия, которые могут возникнуть при изменении кода. Некоторые категории просто несравнимы.

Как можно было бы улучшить эту реализацию? Очевидная идея – использовать подклассы. Например, иерархию классов, представленную в следующем коде, можно применить для реализации различных типов транспортных средств, каждое из которых будет жестко связано с типом двигателя:

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

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

В приведенной архитектуре класс транспортных средств делегирует все поведения, связанные с двигателем, тому объекту-двигателю, которым он обладает. Такой подход иногда называется «иметь», в противоположность предыдущему примеру с подклассами, который называется «быть». Код может проявлять и еще более значительную гибкость, так как он отделяет знания о том, как именно работает двигатель, от информации о машине, в которой этот двигатель установлен. Каждый двигатель делегирует информацию к слабо связанному типу двигателя, и не знает, как этот двигатель реализует свое поведение. В предыдущем примере мы применили многоразовый класс DelegatingVehicle, который совершенно не изменяется, когда мы переходим к работе с новым типом двигателя. Транспортное средство может использовать любую реализацию интерфейса Engine. Кроме того, появляется возможность создавать новые типы транспортных средств (например, спортивный, компактный или роскошный автомобиль) и для каждого из них использовать свой тип Engine.

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

Источник: Android. Программирование на Java для нового поколения мобильных устройств

По теме:

  • Комментарии