Что означает «высокая сплоченность»?

28

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

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

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

Что подразумевается под высокой сплоченностью? Можно ли объяснить пример, чтобы понять его преимущества?

Максимум
источник
1
Разве статья в википедии не дает достаточного ответа на ваш вопрос? en.wikipedia.org/wiki/Cohesion_(computer_science)
Эойн Кэрролл
Хорошая статья об этом есть по адресу: msdn.microsoft.com/en-us/magazine/cc947917.aspx
NoChance
1
@EoinCarroll: К сожалению, в настоящее время статья в Википедии не дает хороших конкретных примеров, с которыми могут работать новые программисты. Теория хороша и все такое, но на самом деле не придерживается, пока вы не совершите ошибки, связанные с низкой сплоченностью. Высокая сплоченность - одна из тех тем, на которые у меня ушло несколько лет программирования, чтобы полностью понять, почему это важно и как этого достичь.
Спойк
Я никогда не понимал единство, пока не прочитал Чистый код. Тебе тоже следует.
Себастьян Редл

Ответы:

25

Один из способов взглянуть на сплоченность в терминах ОО - это если методы в классе используют какой-либо из частных атрибутов. Используя метрики, такие как LCOM4 (Отсутствие связных методов), как указано в этом ответе gnat в этом ответе , вы можете определить классы, которые могут быть реорганизованы. Причина, по которой вы хотите реорганизовать методы или классы, чтобы сделать их более связными, заключается в том, что это упрощает разработку кода для других пользователей . Доверьтесь мне; Большинство технических руководителей и программистов по обслуживанию будут любить вас, когда вы решите эти проблемы.

Вы можете использовать инструменты в процессе сборки, такие как Sonar, чтобы определить низкую сплоченность в базе кода. Есть несколько очень распространенных случаев, когда я могу вспомнить, где методы имеют низкую «сплоченность» :

Случай 1: метод вообще не связан с классом

Рассмотрим следующий пример:

public class Food {
   private int _foodValue = 10;

   public void Eat() {
     _foodValue -= 1;
   }

   public void Replenish() {
     _foodValue += 1;
   }

   public void Discharge() {
     Console.WriteLine("Nnngghhh!");
   }
}

Одному из методов Discharge()не хватает сплоченности, потому что он не касается ни одного из частных членов класса. В этом случае есть только один частный член: _foodValue. Если это ничего не делает с внутренностями класса, то действительно ли оно там? Метод может быть перемещен в другой класс, который может быть назван, например FoodDischarger.

// Non-cohesive function extracted to another class, which can
// be potentially reused in other contexts
public FoodDischarger {
  public void Discharge() {
    Console.WriteLine("Nnngghhh!");
  }
}

Вы делаете это в Javascript, так как функции являются объектами первого класса, разгрузка может быть свободной функцией:

function Food() {
    this._foodValue = 10;
}
Food.prototype.eat = function() {
    this._foodValue -= 1;
};
Food.prototype.replenish = function() {
    this._foodValue += 1;
};

// This
Food.prototype.discharge = function() {
    console.log('Nnngghhh!');
};
// can easily be refactored to:
var discharge = function() {
    console.log('Nnngghhh!');
};
// making it easily reusable without creating a class

Случай 2: класс полезности

Это на самом деле распространенный случай, который нарушает сплоченность. Всем нравятся служебные классы, но они обычно указывают на недостатки проектирования и в большинстве случаев усложняют поддержку кодовой базы (из-за высокой зависимости, связанной с служебными классами). Рассмотрим следующие классы:

public class Food {
    public int FoodValue { get; set; }
}

public static class FoodHelper {

    public static void EatFood(Food food) {
        food.FoodValue -= 1;
    }

    public static void ReplenishFood(Food food) {
        food.FoodValue += 1;
    }

}

Здесь мы видим, что служебный класс должен иметь доступ к свойству в классе Food. Методы в служебном классе в этом случае не имеют никакой сплоченности, потому что для выполнения этой работы нужны внешние ресурсы. В этом случае, не лучше ли иметь методы в классе, с которыми они работают сами по себе (как в первом случае)?

Случай 2b: Скрытые объекты в служебных классах

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

public static class StringUtils {

  public static bool ValidateZipCode(string zipcode) {
    // validation logic
  }

  public static bool ValidatePhoneNumber(string phoneNumber) {
    // validation logic
  }

}

Здесь большинство не осознают, что почтовый индекс, номер телефона или любое другое представление строки могут быть самим объектом:

public class ZipCode {
    private string _zipCode;
    public bool Validates() {
      // validation logic for _zipCode
    }
}

public class PhoneNumber {
    private string _phoneNumber;
    public bool Validates() {
      // validation logic for _phoneNumber
    }
}

Идея о том, что вы не должны «обрабатывать строки» напрямую, подробно описана в этом посте @codemonkeyism , но тесно связана с связностью, потому что программисты используют строки, помещая логику в служебные классы.

Spoike
источник
Теперь, если бы только мы могли заставить наши ORM правильно обрабатывать наши пользовательские классы ZipCode и PhoneNumber: |
Пит
+1 хороший пример. Последний пункт см. Также на sourcemaking.com/refactoring/primitive-obsession
AlexFoxGill,
@Pete Ваш ORM справится с этим, если вы предоставите операторы преобразования из строки в ваш определенный тип (ZipCode, PhoneNumber): msdn.microsoft.com/en-us/library/85w54y0a.aspx
Маркус
9

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

В качестве примера рассмотрим класс, который служит двум или трем целям: загружает / хранит ресурсы (например, файл), а затем анализирует и отображает содержимое. Такой класс обладает низкой связностью, потому что он управляет как минимум двумя отдельными задачами, которые вообще не связаны (файловый ввод-вывод, анализ и отображение). Проект с высокой степенью когезии может использовать различные классы для загрузки и хранения ресурса, его анализа и последующего отображения.

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

zxcdw
источник
7

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

Мировой инженер
источник
разве это не относится и к более высокому уровню, чем просто объекты? например, группировка объектов / функций, связанных с задачей, в пространствах имен?
Стиджн