Qual è il significato di "alta coesione"?

25

Sono uno studente che da poco è entrato a far parte di una società di sviluppo software come stagista. Tornato all'università, uno dei miei professori diceva che dobbiamo lottare per ottenere "Basso accoppiamento e alta coesione".

Capisco il significato di basso accoppiamento. Significa mantenere il codice di componenti separati separatamente, in modo che un cambiamento in un punto non infranga il codice in un altro.

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

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

    
posta Max 31.08.2012 - 04:43
fonte

3 risposte

24

Un modo per osservare 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 , puoi identificare le classi che potrebbero essere refactored. Il motivo per cui si desidera ridefinire metodi o classi per essere più coerenti è che rende più semplice la progettazione del codice perché altri lo utilizzino . Fidati di me; la maggior parte dei lead tecnologici e dei programmatori di manutenzione ti adoreranno quando risolvi questi problemi.

Puoi utilizzare gli strumenti nel processo di compilazione come Sonar per identificare una bassa coesione nella base di codice. Ci sono un paio di casi molto comuni a cui posso pensare dove i metodi sono bassi in "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 c'è un solo membro privato: _foodValue . Se non fa nulla con gli interni della classe, allora ci appartiene davvero? Il metodo potrebbe essere spostato in un'altra classe che potrebbe essere denominata ad esempio FoodDischarger .

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

In te lo stai facendo in Javascript, dal momento che 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. Ognuno di noi ama classi di utilità, ma di solito indicano difetti di progettazione e la maggior parte delle volte rende il codice più complesso 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à ha bisogno di accedere a una proprietà nella classe Food . I metodi nella classe di utilità non hanno affatto coesione in questo caso perché ha bisogno di risorse esterne per fare il suo lavoro. In questo caso, non sarebbe meglio avere i metodi nella classe con cui stanno lavorando (molto come nel primo caso)?

Caso 2b: oggetti nascosti nelle classi di utilità

C'è un altro caso di classi di utilità in cui sono presenti oggetti di dominio non realizzati. La prima reazione istintiva che un programmatore ha quando programmando la manipolazione delle stringhe è di scrivere una classe di utilità per questo. 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 si rende conto 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 dovrebbe "gestire le stringhe" direttamente è descritta in questo blogpost di @codemonkeyism , ma è strettamente correlato alla coesione perché il modo in cui i programmatori usano le stringhe inserendo la logica nelle classi di utilità.

    
risposta data 31.08.2012 - 10:19
fonte
9

Elevata coesione significa mantenere insieme cose simili e correlate, per accoppiare o fondere parti che condividono contenuti, funzionalità, motivo o obiettivo . In altre parole, una bassa coesione potrebbe ad esempio significare un'entità funzione / classe / codice che serve più scopi piuttosto che essere " al punto ". Una delle idee che portano è fare una cosa e farla bene . Altri potrebbero includere il fatto ovvio che non si replicano funzionalità simili in molti posti. Ciò migliora anche la località del codice di base, certi tipi di cose si trovano in un determinato luogo (file, classe, insieme di funzioni, ...) piuttosto che essere sparsi in giro.

Ad esempio, considera una classe che serve due o tre scopi: carica / memorizza le risorse (ad esempio un file), quindi analizza e visualizza il contenuto. Tale classe ha una coesione bassa perché gestisce almeno due attività separate che non sono affatto correlate (I / O di file, analisi e visualizzazione). Un design 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 separate le cose distinte, in modo che interagiscano l'una con l'altra il meno possibile, riducendo quindi la complessità e semplificando la progettazione.

    
risposta data 31.08.2012 - 05:26
fonte
6

Significa che le parti di un dato oggetto sono strettamente correlate alla funzione dell'oggetto. Ciò significa che all'interno dell'oggetto sono presenti scarti minimi o nulli in termini di funzione o responsabilità. Questo a sua volta può migliorare la comprensione di ciò che l'oggetto in questione dovrebbe essere usato per.

    
risposta data 31.08.2012 - 04:58
fonte

Leggi altre domande sui tag