Sunt un student care sa alăturat recent unei companii de dezvoltare software ca stagiar. Înapoi la universitate, unul dintre profesorii mei spunea că trebuie să ne străduim să obținem „Cuplare redusă și coeziune ridicată”.
Înțeleg semnificația cuplării reduse. Înseamnă să păstrezi separat codul componentelor separate, astfel încât o schimbare într-un loc să nu rupă codul în altul.
Dar ce se înțelege prin coeziune ridicată. Dacă înseamnă integrarea bine a diferitelor piese ale aceleiași componente, nu înțeleg cum devine avantajos.
Ce se înțelege prin coeziune ridicată? Se poate explica un exemplu pentru a-i înțelege beneficiile?
Comentarii
- posibil duplicat al Există Valori pentru coeziune și cuplare?
- Articolul din Wikipedia nu răspunde suficient la întrebarea dvs.? en.wikipedia.org/wiki/Cohesion_(computer_science)
- Există un articol bun despre acest lucru la: msdn.microsoft.com/en-us/magazine/cc947917.aspx
- @EoinCarroll: Din păcate, articolul din Wikipedia în momentul actual nu oferă nimic bun exemple concrete cu care pot lucra noii programatori. Teoria este bună și totul, dar ' nu rămâne cu adevărat până când nu ' ați făcut greșelile din jurul coeziunii scăzute. Coeziunea ridicată este unul dintre acele subiecte care mi-au dus câțiva ani de programare să înțeleg pe deplin de ce este important și cum să o realizez.
- Nu am înțeles niciodată cu adevărat Coeziunea până când nu citesc Cod curat. Ar trebui și tu.
Răspuns
Un mod de a privi coeziunea în termeni de OO este dacă metodele din clasa utilizează oricare dintre atributele private. Folosind valori precum LCOM4 (Lipsa metodelor de coeziune), așa cum subliniază gnat în acest răspuns aici , puteți identifica clasele care ar putea fi refactorizate. Motivul pentru care doriți să refactorizați metodele sau clasele pentru a fi mai coeziuni este că face proiectarea codului mai simplă pentru alții să o folosească . Aveți încredere în mine; majoritatea clienților tehnologici și a programatorilor de întreținere vă vor iubi atunci când remediați aceste probleme.
Puteți utiliza instrumente în procesul de compilare, cum ar fi Sonar la identificați o coeziune scăzută în baza codului. Există câteva cazuri foarte frecvente la care mă pot gândi în care metodele sunt scăzute în „coezivitate” :
Cazul 1: Metoda nu are deloc legătură cu clasa
Luați în considerare următorul exemplu:
public class Food { private int _foodValue = 10; public void Eat() { _foodValue -= 1; } public void Replenish() { _foodValue += 1; } public void Discharge() { Console.WriteLine("Nnngghhh!"); } }
Una dintre metode , Discharge()
, lipsește coeziunea deoarece nu atinge niciunul dintre membrii privați ai clasei. În acest caz, există un singur membru privat: _foodValue
. Dacă nu face nimic cu internele clasei, atunci aparține cu adevărat acolo? Metoda ar putea fi mutată într-o altă clasă care ar putea fi denumită de ex. FoodDischarger
.
// Non-cohesive function extracted to another class, which can // be potentially reused in other contexts public FoodDischarger { public void Discharge() { Console.WriteLine("Nnngghhh!"); } }
În ceea ce faceți în Javascript, deoarece funcțiile sunt obiecte de primă clasă, descărcarea poate fi o funcție gratuită:
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
Cazul 2: Utility Class
Acesta este de fapt un caz obișnuit care rupe coeziunea. Toată lumea iubește clasele de utilități, dar acestea indică de obicei defecte de proiectare și de cele mai multe ori face ca baza de cod să fie mai dificil de întreținut (datorită dependenței ridicate asociate claselor de utilități). Luați în considerare următoarele clase:
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; } }
Aici putem vedea că clasa de utilități are nevoie pentru a accesa o proprietate din clasa Food
. Metodele din clasa de utilități nu au deloc coeziune în acest caz deoarece au nevoie de resurse externe pentru a-și face treaba. În acest caz, nu ar fi mai bine să existe metodele din clasa la care lucrează cu ea însăși ( la fel ca în primul caz)?
Cazul 2b: Obiecte ascunse în clasele de utilități
Există un alt caz de clase de utilități în care există obiecte de domeniu nerealizate. Prima reacție de genunchi un programator are atunci când programează manipularea șirului să scrie o clasă de utilitate pentru acesta.La fel ca cel de aici care validează câteva reprezentări de șiruri comune:
public static class StringUtils { public static bool ValidateZipCode(string zipcode) { // validation logic } public static bool ValidatePhoneNumber(string phoneNumber) { // validation logic } }
Ce cele mai multe nu realizează aici este că un cod poștal, un număr de telefon sau orice altă reprezentare șir poate fi un obiect în sine:
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 } }
Noțiunea că nu ar trebui să„ gestionați șirurile ”direct este detaliată în acest post de blog de @codemonkeyism , dar este strâns legat de coeziune deoarece modul în care programatorii folosesc șirurile plasând logica în clasele de utilități.
Comentarii
- Acum, dacă am putea obține ORM-urile noastre pentru a gestiona corect clasele noastre personalizate ZipCode și PhoneNumber: |
- +1 exemple bune. Pentru ultimul punct, consultați și sourcemaking.com/refactoring/primitive-obsession
- @Pete ORM-ul dvs. îl va gestiona dacă furnizați conversie operatori de la șir la tipul dvs. definit (ZipCode, PhoneNumber): msdn.microsoft.com/en-us/library/85w54y0a.aspx
Răspuns
Coeziune ridicată înseamnă să păstrezi lucruri similare și conexe, să cuplezi sau să fuzionezi părți care împărtășesc conținut, funcționalitate, motiv sau scop . Cu alte cuvinte, coeziunea scăzută ar putea, de exemplu, să însemne o entitate funcțională / clasă / cod care servește mai multor scopuri decât să fie „ la obiect ”. Una dintre ideile de transport este să faci un lucru și să o faci bine . Altele ar putea include faptul evident că nu reproduceți funcționalități similare în multe locuri. Aceasta îmbunătățește și localitatea bazei de cod, anumite tipuri de lucruri se găsesc într-un anumit loc (fișier, clasă, set de funcții, …), mai degrabă decât să fie împrăștiate.
De exemplu, luați în considerare o clasă care are două sau trei scopuri: Încarcă / stochează resurse (de exemplu un fișier) și apoi analizează și afișează conținut. O astfel de clasă are coeziune scăzută deoarece gestionează cel puțin două sarcini separate care nu sunt deloc legate (fișier I / O, analiză și afișare). Un design cu coeziune ridicată ar putea utiliza clase distincte pentru încărcarea și stocarea resursei, analiza și apoi afișarea ei.
Pe de altă parte, cuplarea redusă are scopul de a menține lucrurile distincte separate – astfel încât acestea să interacționeze între ele cât mai puțin posibil, ceea ce reduce complexitatea și simplifică designul.
Răspuns
Înseamnă că părțile unui obiect sunt strâns legate de funcția obiectului. Aceasta înseamnă că există foarte puține sau deloc deșeuri în obiect în ceea ce privește funcția sau responsabilitatea. La rândul său, acest lucru poate îmbunătăți înțelegerea pentru ce ar trebui folosit obiectul în cauză.
Comentarii
- nu ' nu se aplică și la un nivel mai înalt decât doar obiectele? de exemplu, gruparea obiectelor / funcțiilor legate de o sarcină în spații de nume?