Qual è il significato di "alta coesione"?


28

Sono uno studente che recentemente è entrato a far parte di una società di sviluppo software come stagista. Di ritorno all'università, uno dei miei professori diceva che dobbiamo sforzarci di raggiungere "Basso accoppiamento e alta coesione".

Capisco il significato di accoppiamento basso. Significa mantenere il codice di componenti separati separatamente, in modo che una modifica in un posto non rompa il codice in un altro.

Ma cosa si intende per alta coesione. Se ciò significa integrare bene i vari pezzi dello stesso componente, non capisco come questo diventi vantaggioso.

Cosa si intende per alta coesione? È possibile spiegare un esempio per comprenderne i vantaggi?



1
L'articolo di Wikipedia non risponde sufficientemente alla tua domanda? en.wikipedia.org/wiki/Cohesion_(computer_science)
Eoin Carroll

C'è un buon articolo su questo a: msdn.microsoft.com/en-us/magazine/cc947917.aspx
NoChance

1
@EoinCarroll: Sfortunatamente l'articolo di Wikipedia al momento non fornisce buoni esempi concreti con cui i nuovi programmatori possono lavorare. La teoria è buona e tutto, ma non si attacca fino a quando non hai fatto gli errori relativi alla bassa coesione. L'alta coesione è uno di quegli argomenti che mi ha richiesto diversi anni di programmazione per capire appieno perché è importante e come raggiungerlo.
Spoike,

Non ho mai veramente capito la coesione fino a quando non ho letto Clean Code. Dovresti anche tu.
Sebastian Redl,

Risposte:


25

Un modo di considerare la coesione in termini di OO è se i metodi nella classe utilizzano uno degli attributi privati. Utilizzando metriche come LCOM4 (Mancanza di metodi coesivi), come sottolineato da Gnat in questa risposta qui , è possibile identificare le classi che potrebbero essere refactored. Il motivo per cui si desidera riformattare i metodi o le classi in modo che siano più coerenti è che semplifica la progettazione del codice per gli altri . Fidati di me; la maggior parte dei lead tecnologici e dei programmatori di manutenzione ti adoreranno quando risolvi questi problemi.

È possibile utilizzare strumenti nel processo di generazione come Sonar per identificare una bassa coesione nella base di codice. Ci sono un paio di casi molto comuni a cui riesco a pensare dove i metodi hanno poca "coesione" :

Caso 1: il metodo non è affatto correlato alla classe

Considera il seguente esempio:

public class Food {
   private int _foodValue = 10;

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

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

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

Uno dei metodi Discharge()manca di coesione perché non tocca nessuno dei membri privati ​​della classe. In questo caso v'è un solo membro privato: _foodValue. Se non fa nulla con gli interni della classe, allora appartiene davvero lì? Il metodo potrebbe essere spostato in un'altra classe che potrebbe essere denominata ad es FoodDischarger.

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

Nel farlo in Javascript, poiché le funzioni sono oggetti di prima classe, lo scarico può essere una funzione gratuita:

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

Caso 2: classe di utilità

Questo è in realtà un caso comune che rompe la coesione. Tutti amano le classi di utilità, ma di solito indicano difetti di progettazione e la maggior parte delle volte rende la base di codice più difficile da mantenere (a causa dell'alta dipendenza associata alle classi di utilità). Considera le seguenti classi:

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;
    }

}

Qui possiamo vedere che la classe di utilità deve accedere a una proprietà nella classe Food. I metodi nella classe di utilità non hanno affatto coesione in questo caso perché hanno bisogno di risorse esterne per funzionare. In questo caso, non sarebbe meglio avere i metodi nella classe che stanno lavorando con se stesso (proprio come nel primo caso)?

Caso 2b: oggetti nascosti nelle classi di utilità

Esiste un altro caso di classi di utilità in cui sono presenti oggetti di dominio non realizzati. La prima reazione istintiva che un programmatore ha durante la programmazione della manipolazione di stringhe è quella di scrivere una classe di utilità per essa. Come quello qui che convalida un paio di rappresentazioni di stringhe comuni:

public static class StringUtils {

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

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

}

Ciò che la maggior parte non capisce qui è che un codice postale, un numero di telefono o qualsiasi altra rappresentazione di stringa può essere un oggetto stesso:

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
    }
}

L'idea che non si debba "gestire direttamente le stringhe" è dettagliata in questo post di @codemonkeyism , ma è strettamente correlata alla coesione perché il modo in cui i programmatori usano le stringhe inserendo la logica nelle classi di utilità.


Ora, se solo potessimo convincere i nostri ORM a gestire correttamente le nostre classi ZipCode e PhoneNumber personalizzate: |
Pete,

+1 buoni esempi. Per l'ultimo punto, vedi anche sourcemaking.com/refactoring/primitive-obsession
AlexFoxGill

@Pete Il tuo ORM lo gestirà se fornisci operatori di conversione da stringa al tipo definito (Codice postale, Numero di telefono): msdn.microsoft.com/en-us/library/85w54y0a.aspx
Marcus

9

Alta coesione significa tenere insieme cose simili e correlate, accoppiare o fondere parti che condividono contenuto, funzionalità, ragione o obiettivo . In altre parole, una bassa coesione potrebbe ad esempio significare un'entità funzione / classe / codice che serve a molteplici scopi anziché essere " al punto ". Una delle idee portanti è fare una cosa e farlo bene . Altri potrebbero includere il fatto ovvio che non replicare funzionalità simili in molti luoghi. Ciò migliora anche la localizzazione della base di codice, alcuni tipi di cose si trovano in un determinato posto (file, classe, set di funzioni, ...) piuttosto che essere sparsi in giro.

Ad esempio, considera una classe che ha due o tre scopi: Carica / memorizza risorse (ad esempio un file) e quindi analizza e visualizza il contenuto. Tale classe ha una bassa coesione perché gestisce almeno due attività separate che non sono affatto correlate (I / O dei file, analisi e visualizzazione). Un progetto ad alta coesione potrebbe utilizzare classi distinte per caricare e archiviare la risorsa, analizzarla e quindi visualizzarla.

D'altra parte, l'accoppiamento basso mira a mantenere separati elementi distinti, in modo che interagiscano l'uno con l'altro il meno possibile, riducendo quindi la complessità e semplificando il design.


7

Significa che le parti di un determinato oggetto sono strettamente correlate alla funzione dell'oggetto. Ciò significa che all'interno dell'oggetto ci sono pochissimi o nessun rifiuto in termini di funzione o responsabilità. Questo a sua volta può migliorare la comprensione di ciò per cui l'oggetto in questione dovrebbe essere utilizzato.


non si applica anche a un livello superiore rispetto agli oggetti? ad es. raggruppamento di oggetti / funzioni relativi a un'attività in spazi dei nomi?
stijn,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.