Улучшение сплоченности и сцепления классов - PullRequest
2 голосов
/ 16 июня 2011

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

1 голос
/ 17 июня 2011

Начните писать модульные тесты (еще лучше, сделайте TDD ). Связь (и, в меньшей степени, когезия или ее отсутствие) станет сразу очевидным.

Например, метод запуска класса B имеет параметр типа A. В вашем примере вы могли бы просто создать экземпляр A, но что если у A были другие зависимости? Возможно, все, что нужно для запуска, - это интерфейс, который реализует A (с методом обновления).

А что делает getNextEvent? Если он использует другие зависимости, получение B в тестовом жгуте может оказаться затруднительным.

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

0 голосов
/ 17 июня 2011

Одним из предложений будет отделение логики обработки событий от логики контроллера (класс 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) и обработчик (ваш метод обновления (e)) слабо связанными

0 голосов
/ 17 июня 2011

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

0 голосов
/ 16 июня 2011

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

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

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

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

...