en introduktion till solid-principerna
DESCRIPTION
An introduction to the SOLID principles in Swedish that I gave at the EPiServer developers meetup in june 2010. You probably need to read the comments to understand some of the slides.TRANSCRIPT
En introduktion till SOLID principerna
Hur uncle Bob förändrade mitt liv
@joelabrahamsson
Agile Principles, Patterns and Practices in C#
• UML (as a sketch)• Patterns • Agila arbetssätt som XP, TDD och
Refactoring• Designprinciper för klasser och
paket/assemblies
Single Responsibility Principle
Open/Closed Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
SOLID
• Fem priciper för objektorienterad utveckling• Hantera beroenden mellan klasser och
reducera onödig komplexitet• Underlättar testning• Principer, inte lagar• Kräver att studeras
Single Responsibility Principle
En klass bör ha en, och endast en, anledning att ändras.
Med andra ord...
En klass ska bara göra en sak.
Exempel
public class Customer{ public IEnumerable<Order> Orders { get {...} }
public bool IsValid() {...}
public void Save() {...}}
Single Responsibility Principle
• Är även applicerbar på metoder, paket/assemblies etc.
• Ligger till grund för många av de andra principerna
Open/Closed Principle
Klasser ska vara öppna för utökning men stängda för modifiering.
Med andra ord...
Vi bör använda arv och polymorfism för att skriva kod som inte behöver ändras när kraven gör det.
Exempel
Vi behöver en klass som beräknar arean för ett antal rektanglar.
public class Rectangle{ public double Width { get; set; } public double Height { get; set; }}
Let’s do it!public class AreaCalculator{ public double Area(Rectangle[] shapes) { double area = 0; foreach (var shape in shapes) { area += shape.Width*shape.Height; }
return area; }}
Ett nytt krav
Vi glömde att det finns cirklar. Vi behöver beräkna arean för både cirklar och rektanglar.
En basklass och en if-sats -> Done!public abstract class Shape { }
public class AreaCalculator{ public double Area(Shape[] shapes) { double area = 0; foreach (var shape in shapes) { if (shape is Rectangle) area += RectangleArea((Rectangle)shape); else area += CircleArea((Circle) shape); }
return area; }}
En bättre lösningpublic abstract class Shape{ public abstract double Area();}
public class AreaCalculator{ public double Area(Shape[] shapes) { double area = 0; foreach (var shape in shapes) { area += shape.Area(); }
return area; }}
• Den viktigaste av principerna• Kraven ändras ständigt…• …men vi behöver ändå skriva kod som är
stabil• Med OO kan vi skapa abstraktioner med stabil
design men flexibelt beteende• När ska vi applicera principen?
Open/Closed Principle
Dependency Inversion Principle
A. Högnivåmoduler ska inte vara beroende av lågnivåmoduler. Båda ska vara beroende av abstraktioner.
B. Abstraktioner ska inte vara beroende av detaljer. Detaljer ska vara beroende av abstraktioner.
Med andra ord...
Våra klasser ska inte vara beroende av andra klasser. De ska vara beroende av abstraktioner.
• Möjliggör att en klass kan använda en annan komponent utan att känna till vilken specifik implementation det är
• Åstadkoms genom Dependency Injection eller Service Locator
Inversion of Control
Ett exempel
IoC leder till flexibel design
• Den som använder vår klass måste tillhandahålla instanser av de klasser som den behöver
• Constructor Injection• Property Injection
Dependency Injection
• The consumer retrieves the component it depends upon from a third party, a Service Locator
• Use Dependency Injection instead if you can
Service Locator
Liskov Substitution Principle
Subklasser måste vara utbytbara mot dess basklasser.
Med andra ord...
Användare av vår subklass ska inte behöva bry sig om huruvida de använder subklassen eller basklassen.
Ett enkelt exempelpublic abstract class Animal{ public abstract void MakeNoise();}
Ett enkelt exempelpublic class Cat : Animal{ public override void MakeNoise() { Console.WriteLine("Mjau"); }}
Ett enkelt exempelpublic class Snail : Animal{ public override void MakeNoise() { throw new NotImplementedException(); }}
Liskov Substitution Principle
• Det är OK att försvaga förhandsvillkor och stärka efterhands-villkor i en subklass men inte tvärtom.
• Om vi bryter mot LSP så tyder det på att vi behöver refaktorisera vår klasshierarki
• En princip, inte en lag
Interface Segregation Principle
Användare av ett interface ska inte tvingas vara beroende av metoder som de inte använder.
Med andra ord...
Skapa interface som är små och logiskt sammanhängande.
Exempel - IPageSourcepublic interface IPageSource{ PageDataCollection GetChildren(PageReference pageLink); PageData GetPage(PageReference pageLink); PageData CurrentPage { get; }}
Exempel - IPageSourcepublic class DataFactory : IPageSource{ public PageData GetPage(PageReference pageLink) { ... } public PageData GetChildren(PageReference pageLink) { ... }
public PageData CurrentPage { get { return null; } }}
Mer om SOLID-principerna
• Agile Principles, Patterns and Practices in C#• butunclebob.com• blog.objectmentor.com• Stefan Forsbergs serie på EPiServer World• www.codingefficiency.com
Mer av uncle Bob
Sammanfattning
• Uncle Bob, Robert C.Martin, är en författare vi kan lära mycket av
• Läs Agile Principles, Patterns and Practices in C#!
• Läs Clean Code!• SOLID är fem principer för objekt orienterad
utveckling som hjälper oss hantera beroenden och komplexitet
@joelabrahamssonhttp://joelabrahamsson.com