Улучшение сплоченности и сцепления классов
Мне дан этот набор кода, и мне нужно предложить способы улучшить целостность кода и сцепление классов. Но я думал, что эти классы довольно хорошо разделены, так как похоже, что они используют события. И с точки зрения сплоченности, все вызовы init() размещены вместе, мне кажется, все в порядке.
public class A
{
private C t;
private B g;
public static void main(String args[]) {
// Creates t and g.
t = new C();
t.init();
g = new B();
g.init();
g.start(this);
}
pubic void update (Event e)
{
// Performs updating of t based on event
}
}
public class C
{
public C() { ... }
public void init() { ... }
}
public class B
{
public B() { ... }
public void init() { ... }
public void start(A s) {
e = getNextEvent();
while (e. type != Quit)
if (e.type == updateB)
update(e) ;
else
s.update(e) ;
e = getNextEvent();
}
public void update(Event e) { ... }
}
}
Есть ли еще способы улучшить сцепление классов и сцепление? Это выглядит нормально для меня, но я думаю, что что-то упустил.
Спасибо за любые предложения по этому вопросу.
4 ответа
Одно из предложений - отделить логику обработки событий от логики контроллера (класс A).
Таким образом, у вас будет 4 типа классов:
- основной класс, используемый для запуска "сервера" (A)
- поток, слушающий события (B)
- слой модели, который будет обновлен (C)
- класс обработчика событий, который будет поддерживать некоторые операции над событием (D)
Это может выглядеть примерно так:
public class Main {
private Model m;
private EventListener listener;
... main() {
m = new Model();
listener = new EventListener();
EventHandler eventHandler = new MyEventHandler();
// set the event handler
listener.setEventHandler(eventHandler);
listener.start(m);
}
public class Model {
// nothing to see here
}
public class EventListener() {
private EventHandler handler = new DefaultEventHandler();
public void start(final Model m) {
// startup
while (event.type != Event.Quit) {
// get event
handler.handleEvent(event, m);
}
// shutdown
}
public void setEventHandler(EventHandler eh) { this.handler = eh }
}
public class MyEventHandler implements EventHandler {
public void handleEvent(Event e, Model m) {
// update the model
}
}
Обратите внимание, что в этом новом дизайне бизнес-логика обновления модели (C в вашем примере) переместилась во внешний класс, а не в класс "Runner". это немного чище, так как классу Main не нужно знать, что такое события и как их обрабатывать.
Другое преимущество заключается в том, что с его помощью вы можете легко кодировать сложную обработку событий, используя цепочечные обработчики событий или несколько последовательных обработчиков событий. Также довольно просто реализовать асинхронную обработку событий, так как B отвечает только за вызов обработчиков и не нуждается в понимании типов событий. Это иногда называется публикацией / подпиской и поддерживает слабую связь слушателя (B) и обработчика (ваш метод update(e))
Начните писать модульные тесты (еще лучше, сделайте TDD). Связь (и, в меньшей степени, когезия или ее отсутствие) станет сразу очевидным.
Например, метод start класса B имеет параметр типа A. В вашем примере вы могли бы просто создать экземпляр A, но что если у A были другие зависимости? Возможно, все потребности запуска - это интерфейс, который реализует A (с методом обновления).
А что делает getNextEvent? Если он использует другие зависимости, получение B в тестовом жгуте может оказаться трудным.
Тестирование может помочь подтвердить ваш дизайн.
Если исходный дизайн должен включать в себя другую функциональность или классы в будущем, используя обработчик событий, как вы сказали, он использовался, тогда просто сконцентрируйтесь на шаблоне стратегии на реализации и оптимизации на классах или интерфейсах.
Не видя больше вашего кода, трудно сказать, насколько отделен ваш код. События являются одним из способов разъединения кода, но также могут усложнить понимание и отладку кода.
При разработке классов высокая когезия означает, что многие методы повторно используют друг друга, а низкая связь означает, что вам нужно только представить несколько открытых методов.
При разработке пакетов высокая когезия означает, что многие классы в пакете зависят друг от друга, а низкая связь означает, что лишь немногие являются общедоступной областью действия или сообщением с другими классами через интерфейсы.
Преимущества высокого сцепления и низкого сцепления должны быть меньше боли, особенно когда дело доходит до реагирования на изменения. Если это не уменьшает боль, не тратьте много времени на ее оптимизацию. Я знаю, это звучит так, как будто я излагаю здесь банальности, но вы должны помнить о своей собственной метрике, измеряя, является ли высокая сплоченность, слабая связь "достаточно хорошей", а не полагаться на мнения людей, которые не обязательно понимают проблема, которую вы пытаетесь решить.