[Java] Факторизация программы с разнотипными колбэками от "железа"

nikola1956

Подскажите, пожалуйста, как лучше факторизовать класс, который реализует несколько интерфейсов, представляющих собой колбэки от разных типов внешних устройств (камеры, акселерометра, графического потока, автофокусировки и т.п.) ?
Более точно, есть класс A, который реализует интерфейсы от "железа" D_1, D_2, .. D_k. Каждый из интерфейсов привносит в класс A несколько методов, которые нужно реализовать. Соответственно класс A достигает ужасающих размеров, причем использует дополнительные группы переменных, констант и вспомогательных методов (функций которые относятся к работе в точности с одним из интерфейсов (одна группа переменных, констант и функций — для камеры, другая — для гироскопа или акселерометра и т.п.).
Естественно возникает желание разделить реализации разных интерфейсов по разным файлам и классам (как бы "проекциям" интерфейсов на класс A). Но как это проще всего сделать ? Ведь в Java нет возможности расширения классов как в Ruby или, например, типажей (trait) как в Scala.

Dasar

можно руками запроксировать интерфейсы (часть или все)
исходный класс A преобразуется в прокси, перенаправляющий все вызовы в реальные реализации интерфейсов

class A:D_1
{
public A
{
d1 = new A_D_1;
}
D_1 d1;

public T D_1_Method1(..)
{
return d1.D_1_Method1(..);
}
public T D_1_Method2(..)
{
return d1.D_1_Method2(..);
}
...
}

реализацию интерфейса выносим в отдельный класс

class A_D1:D_1
{
public T D_1_Method1(..)
{
//здесь делаем что-то реальное
}

}

зы
есть утилиты, которые автоматизируют создание такого прокси и поддержание его в актуальном состоянии

nikola1956

Большое спасибо за полезный ответ ! :)
Похожая идея возникала и у меня: заменить реализацию интерфейса D на поле d класса A, которое является объектом класса D`, реализующего интерфейс D.
Правда, до Вашего ответа, я не знал, что это в некотором смысле стандартный способ решения проблем проектирования, описанных мной выше. Если я правильно понял, ища в инете по ключевому слову "прокси", то предложенное Вами решение — это шаблон проектирования Proxy (Заместитель).

Dasar

Если я правильно понял, ища в инете по ключевому слову "прокси", то предложенное Вами решение — это шаблон проектирования Proxy (Заместитель).
да, это он и есть

katrin2201

АПИ той библиотеки, которая принимает на вход ваш большой класс - там точно необходимо, чтобы был _один_ объект, реализующий _все_ интерфейсы?
Обычно можно в качесте разных коллбэков передавать разные объекты/классы.
В этом случае не надо никаких прокси. Руками (или рефакторингом) разбиваешь своего монстра на несколько классов, и все использования класса-монстра заменяешь на использование соотв маленького класса.
ЗЫ А прокси в джаве можно сделать на основе рефлекшена - тогда не надо будет каждый раз кодогенерить делегирующий монстрокласс - он сам будет разбираться в рантайме какой метод какому делегату проксирвать. Но это, конечно, пефоманс хит.

nikola1956

АПИ той библиотеки, которая принимает на вход ваш большой класс - там точно необходимо, чтобы был _один_ объект, реализующий _все_ интерфейсы?.
Кстати, да, это не необходимо :)
Обычно можно в качесте разных коллбэков передавать разные объекты/классы.
В этом случае не надо никаких прокси. Руками (или рефакторингом) разбиваешь своего монстра на несколько классов, и все использования класса-монстра заменяешь на использование соотв маленького класса

Возможно, это очень хорошая идея, но я еще до конца не продумал детали. Действительно, можно мыслить в терминах нескольких "объектов-потоков": главный объект — это основной поток, разнотипные устройства (и их колбэки) — это его дочерние объекты-потоки; + имеются разнообразные попарные направленные связи между объектами, по которым одни объекты изменяют внутренние состояния других. Рисуем ориентированный граф взаимодействий и указываем методы взаимодействия ...
Например, акселерометр (1) запускает автофокус (2 автофокус переходит в состояние "ЗАПУЩЕН"; автофокус, оказавшийся в состоянии "ПОЙМАН (НАЙДЕН)", запускает фотографирование (3); фотографирование в состоянии "СДЕЛАНО" запускает "распознаватель" (4 на которого воздействовал объект-поток "сенсор освещенности" (5) и объект-поток "быстрый распознаватель" (6 на которого воздействовала камера (7 на которую в свою очередь воздействовал гироскоп (8) и т.д. и т.п.

katrin2201

Возможно, это очень хорошая идея, но я еще до конца не продумал детали. Действительно, можно мыслить в терминах нескольких "объектов-потоков"
На мой взгляд только так и надо. Иначе в чем смысл разбиения по колбэкам, если состояние/логика для всего все равно живет в одном классе? Только не понял, зачем ты сюда потоки приплел, но подозреваю, что это какие-то другие потоки, нежели чем привычный Thread.
Если близок паттерн MVC, то в твоем случае контроллеры - это как бы коллбэки, модель - это состояние, а вью - это библиотека, которая дергает твои коллбэки. И помни об этом.
Если все равно тяжеловато, но хочется сделать красиво и есть время - попробуй заботать TDD - немножко рушит мозг, но со временем хорошо учит писать красивый код.

Dimon89

попробуй заботать TDD - немножко рушит мозг, но со временем хорошо учит писать красивый код.
Кстати +1. Как раз тот случай, когда неделя обучения экономит месяц отладки, имхо.
Оставить комментарий
Имя или ник:
Комментарий: