Улучшение сплоченности и сцепления классов

Мне дан этот набор кода, и мне нужно предложить способы улучшить целостность кода и сцепление классов. Но я думал, что эти классы довольно хорошо разделены, так как похоже, что они используют события. И с точки зрения сплоченности, все вызовы 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 в тестовом жгуте может оказаться трудным.

Тестирование может помочь подтвердить ваш дизайн.

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

Не видя больше вашего кода, трудно сказать, насколько отделен ваш код. События являются одним из способов разъединения кода, но также могут усложнить понимание и отладку кода.

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

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

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

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