Jeg er studerende, der for nylig blev medlem af en softwareudviklingsvirksomhed som praktikant. Tilbage på universitetet plejede en af mine professorer at sige, at vi skal stræbe efter at opnå “Lav kobling og høj samhørighed”.
Jeg forstår betydningen af lav kobling. Det betyder at holde koden for separate komponenter separat, så en ændring et sted ikke bryder koden et andet.
Men hvad menes der med høj samhørighed. Hvis det betyder at integrere de forskellige stykker af den samme komponent godt med hinanden, forstår jeg ikke, hvordan det bliver fordelagtigt.
Hvad menes der med høj samhørighed? Kan et eksempel forklares for at forstå fordelene?
Kommentarer
- mulig duplikat af Er der Metrics For Cohesion And Coupling?
- Svarer wikipedia-artiklen ikke dit spørgsmål tilstrækkeligt? da.wikipedia.org/wiki/Cohesion_(computer_science)
- Der er en god artikel om dette på: msdn.microsoft.com/en-us/magazine/cc947917.aspx
- @EoinCarroll: Desværre giver wikipedia-artiklen i øjeblikket ikke noget godt konkrete eksempler som nye programmører kan arbejde med. Teorien er god og alt sammen, men holder ikke ' virkelig, indtil du ' har lavet fejlene omkring lav samhørighed. Høj samhørighed er et af de emner, der har taget mig flere års programmering for fuldt ud at forstå, hvorfor det er vigtigt, og hvordan at opnå det.
- Jeg forstod aldrig rigtig samhørighed, før jeg læste Ren kode. Det skal du også.
Svar
En måde at se på samhørighed i form af OO er, hvis metoderne i klassen bruger nogen af de private attributter. Ved hjælp af metrikker som LCOM4 (Mangel på sammenhængende metoder), som påpeget af gnat i dette svar her , kan du identificere klasser, der kan refaktoriseres. Årsagen til, at du vil omformulere metoder eller klasser for at være mere sammenhængende er, at det gør kodedesignet lettere for andre at bruge det . Stol på mig; de fleste tekniske kundeemner og vedligeholdelsesprogrammerere vil elske dig, når du løser disse problemer.
Du kan bruge værktøjer i din byggeproces, f.eks. Ekkolod til identificere lav samhørighed i kodebasen. Der er et par meget almindelige tilfælde, som jeg kan tænke på, hvor metoderne er lave i “sammenhængskraft” :
Tilfælde 1: Metoden er slet ikke relateret til klassen
Overvej følgende eksempel:
public class Food { private int _foodValue = 10; public void Eat() { _foodValue -= 1; } public void Replenish() { _foodValue += 1; } public void Discharge() { Console.WriteLine("Nnngghhh!"); } }
En af metoderne , Discharge()
, mangler samhørighed, fordi den ikke rører nogen af klassens private medlemmer. I dette tilfælde er der kun ét privat medlem: _foodValue
. Hvis det ikke gør noget med klasseinterne, så hører det der virkelig med? Metoden kunne flyttes til en anden klasse, der kunne navngives f.eks. FoodDischarger
.
// Non-cohesive function extracted to another class, which can // be potentially reused in other contexts public FoodDischarger { public void Discharge() { Console.WriteLine("Nnngghhh!"); } }
I dig “gør du det i Javascript, da funktioner er førsteklasses objekter, udladningen kan være en gratis funktion:
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
Tilfælde 2: Hjælpeklasse
Dette er faktisk en almindelig sag, der bryder samhørighed. Alle elsker nytteklasser, men disse indikerer normalt designfejl og gør det meste af tiden kodebasen vanskeligere at vedligeholde (på grund af den høje afhængighed forbundet med hjælpeklasser). Overvej følgende klasser:
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; } }
Her kan vi se, at hjælpeklassen har brug for for at få adgang til en ejendom i klassen Food
. Metoderne i forsyningsklassen har slet ikke nogen sammenhæng i dette tilfælde, fordi det har brug for eksterne ressourcer til at udføre det. I dette tilfælde ville det ikke være bedre at have metoderne i den klasse, de arbejder med sig selv ( meget som i det første tilfælde)?
Tilfælde 2b: Skjulte objekter i Hjælpeklasser
Der er et andet tilfælde af hjælpeklasser, hvor der er urealiserede domæneobjekter. Den første kneb-reaktion en programmør har, når programmering af strengmanipulation er at skrive en hjælpeklasse til den.Som den her, der validerer et par almindelige strengrepræsentationer:
public static class StringUtils { public static bool ValidateZipCode(string zipcode) { // validation logic } public static bool ValidatePhoneNumber(string phoneNumber) { // validation logic } }
Hvad de fleste ved ikke her, at et postnummer, et telefonnummer eller en hvilken som helst anden strengrepræsentation kan være et objekt i sig selv:
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 } }
Forestillingen om, at du ikke” skal “håndtere strenge” er detaljeret i denne blogindlæg af @codemonkeyism , men er tæt knyttet til samhørighed, fordi den måde, programmører bruger strenge ved at sætte logik i hjælpeklasser.
Kommentarer
- Nu hvis vi kun kunne få vores ORMer til korrekt håndtering af vores brugerdefinerede ZipCode- og PhoneNumber-klasser: |
- +1 gode eksempler. For det sidste punkt, se også sourcemaking.com/refactoring/primitive-obsession
- @Pete Din ORM håndterer det, hvis du leverer konvertering operatører fra streng til din definerede type (ZipCode, PhoneNumber): msdn.microsoft.com/en-us/library/85w54y0a.aspx
Svar
Høj samhørighed betyder at holde lignende og relaterede ting sammen, at parre eller smelte dele, der deler indhold, funktionalitet, grund eller mål . Med andre ord kan lav samhørighed for eksempel betyde en funktion / klasse / kodeenhed, der tjener flere formål i stedet for at være “ til punktet “. En af de bærende ideer er at gøre en ting og gøre det godt . Andre kan omfatte det åbenlyse faktum, at du ikke replikerer lignende funktionalitet mange steder. Dette forbedrer også lokalitet af kodebasen, visse slags ting findes på et bestemt sted (fil, klasse, sæt af funktioner, …) i stedet for at være spredt rundt.
Som et eksempel skal du overveje en klasse, der tjener to eller tre formål: Indlæser / lagrer ressourcer (for eksempel en fil) og analyserer og viser derefter En sådan klasse har lav samhørighed, fordi den administrerer mindst to separate opgaver, der slet ikke er relateret (fil I / O, analyse og visning). Et design med høj samhørighed kunne bruge forskellige klasser til at indlæse og lagre ressourcen, analysere den og derefter vise den.
På den anden side har lav kobling til formål at holde adskilte ting adskilt – så de interagerer med hinanden så lidt som muligt, hvilket derefter reducerer kompleksiteten og forenkler designet.
Svar
Det betyder, at delene af et objekt er tæt knyttet til objektets funktion. Dette betyder, at der er meget lidt eller intet spild inden for objektet med hensyn til funktion eller ansvar. Dette kan igen forbedre forståelsen af, hvad det pågældende objekt skal bruges til.
Kommentarer
- betyder ikke ' t gælder det også for et højere niveau end kun objekter? fx at gruppere objekter / funktioner relateret til en opgave i navneområder?