paint-brush
11 modele cheie de design: un ghid esențialde@ssukhpinder
Noua istorie

11 modele cheie de design: un ghid esențial

de Sukhpinder Singh33m2024/09/08
Read on Terminal Reader

Prea lung; A citi

Descoperiți secretele arhitecturii software cu *Mastering Software Architecture: 11 Key Design Patterns Explained*. Cartea este scrisă în limbajul de programare C# C# 8.0. Există 11 modele de design care pot fi folosite pentru a crea o fabrică pentru crearea de fabrici. Modelul de fabrică abstract este o metodă de fabrica de extensie; se recomandă să treceți prin metoda din fabrică.
featured image - 11 modele cheie de design: un ghid esențial
Sukhpinder Singh HackerNoon profile picture
0-item
1-item
2-item
3-item
4-item

Deblocați secretele arhitecturii software cu Mastering Software Architecture: 11 Key Design Patterns Explained .

Cuprins

  1. Model de design — Fabrica de abstracte
  • Obiectivele de învățare
  • Noțiuni de bază
  • Cum să utilizați un furnizor abstract de fabrică?
  • Ieșire

2. Model de proiectare — Adaptor

  • Caz de utilizare
  • Obiectivele de învățare
  • Noțiuni de bază

3. Design Pattern — Builder

  • Caz de utilizare
  • Obiectivele de învățare
  • Noțiuni de bază
  • Cum se utilizează modelul de constructor din metoda Main().
  • Ieșire

4. Cum să utilizați modelul de lanț de responsabilitate

  • Caz de utilizare
  • Noțiuni de bază
  • Cum se utilizează modelul Lanțului de responsabilitate?
  • Ieșire

5. Model de design — Decorator

  • Caz de utilizare
  • Obiectivele de învățare
  • Noțiuni de bază
  • Decorator Pattern în acțiune
  • Cod complet
  • Ieșire

6. Model de proiectare — Metoda fabricii

  • Obiectivele de învățare
  • Noțiuni de bază
  • Cum se folosește metoda din fabrică?
  • Ieșire

7. Model de proiectare — Iterator

  • Caz de utilizare
  • Noțiuni de bază
  • Model iterator în acțiune
  • Ieșire

8. Design Pattern — Mediator

  • Caz de utilizare
  • Obiectivele de învățare
  • Noțiuni de bază
  • Cum să utilizați modelul mediator din metoda principală

9. Model de design — Observator

  • Caz de utilizare
  • Obiectivele de învățare
  • Noțiuni de bază
  • Cum se folosește un model de observator?
  • Ieșire

10. Advance Property Pattern C# 8.0

  • Să începem
  • Program de potrivire a modelelor cu noua sintaxă de comutare
  • Program de testare
  • Ieșire consolă

11. Model de design — Singleton

  • Obiectivele de învățare
  • Noțiuni de bază
  • Ieșire
  • Siguranța firului

Model de design — Fabrica de abstracte

Potrivit Gang of Four, modelele abstracte ale fabricii pot fi presupuse ca fiind fabrica pentru crearea fabricilor.


Obiectivele de învățare

  • Care este modelul de design abstract al fabricii?
  • Cum se scrie cod folosind modelul abstract de design din fabrică?
  • Cum se creează un furnizor de fabrică?
  • Cum se creează o aplicație client (din metoda Main) care utilizează un furnizor din fabrică

Cerințe preliminare

Modelul abstract de fabrică este pur o metodă de fabrică de extensie; se recomandă să treceți prin metoda fabricii înainte de a înțelege designul abstract al fabricii.

  • Cunoștințe de bază ale conceptelor OOPS.
  • Orice cunoștințe de limbaj de programare.

Noțiuni de bază

Să luăm în considerare același exemplu de orice bancă cu tipuri de conturi, cum ar fi conturi de economii și conturi curente. Acum, să implementăm exemplul de mai sus folosind modelul abstract de design din fabrică.


În primul rând, implementați interfețele ISavingAccount și ICurrentAccount după cum urmează:


 public interface ISavingAccount{ } public interface ICurrentAccount{ }


Moșteniți interfața în clasele de mai jos


 public class CurrentAccount : ICurrentAccount { public CurrentAccount(string message) { Console.WriteLine(message); } } public class SavingsAccount : ISavingAccount { public SavingsAccount( string message) { Console.WriteLine(message); } }


Să scriem o clasă abstractă cu metode abstracte pentru fiecare tip de cont.


 public abstract class AccountTypeFactory { public abstract ISavingAccount SavingAccountFactory(string message); public abstract ICurrentAccount CurrentAccountFactory(string message); }


Acum, să creăm o implementare din fabrică numită „Bank1Factory”, care oferă implementarea metodelor abstracte.


 public class Bank1Factory : AccountTypeFactory { public override ICurrentAccount CurrentAccountFactory(string message) { return new CurrentAccount(message); } public override ISavingAccount SavingAccountFactory(string message) { return new SavingsAccount(message); } }


Modelul abstract de proiectare a fabricii diferă de metoda din fabrică de care are nevoie pentru a implementa un furnizor de fabrică, care returnează fabrici conform definiției.


Acum că avem toate abstracțiile și fabricile create. Să proiectăm furnizorul fabricii. Vă rugăm să găsiți mai jos fragmentul de cod pentru furnizorul fabricii, unde o metodă statică va crea o fabrică pe baza numelui contului.


 public class AccountFactoryProvider { public static AccountTypeFactory GetAccountTypeFactory(string accountName) { if (accountName.Contains("B1")) { return new Bank1Factory(); } else return null; } }

Cum să utilizați un furnizor abstract Factory?

Să luăm un exemplu de listă de numere de cont în care, dacă un nume de cont constă literalmente din „ B1 ”, atunci va folosi instanța Bank1Factory returnată prin furnizorul din fabrică.

 static void Main(string[] args) { List<string> accNames = new List<string> { "B1-456", "B1-987", "B2-222" }; for (int i = 0; i < accNames.Count; i++) { AccountTypeFactory anAbstractFactory = AccountFactoryProvider.GetAccountTypeFactory(accNames[i]); if (anAbstractFactory == null) { Console.WriteLine("Invalid " + (accNames[i])); } else { ISavingAccount savingAccount = anAbstractFactory.SavingAccountFactory("Hello saving"); ICurrentAccount currentAccount = anAbstractFactory.CurrentAccountFactory("Hello Current"); } } Console.ReadLine(); }


Dacă numele contului nu conține literalul „B1”, atunci programul va scoate un {{accountName}} nevalid

Ieșire

Vă rugăm să găsiți mai jos rezultatul din fragmentul de cod de mai sus.


 Hello saving B1-456 Hello Current B1-456 Hello saving B1-987 Hello Current B1-987

Model de design — Adaptor

Potrivit Gang of Four, Adapter Pattern convertește interfețele unei clase în interfețe pe care clientul le cere.


Cu alte cuvinte, modelul de design al adaptorului ajută interfețele incompatibile să funcționeze colectiv.

Caz de utilizare

Să luăm în considerare un exemplu de fuziune a două organizații; Organizația X preia Y, dar în timp ce combină codul, interfețele nu sunt compatibile. Să presupunem că interfața care oferă o listă de tranzacții ale organizației Y nu este compatibilă cu X.


Deci, modelul de design al adaptorului ajută la rezolvarea acestei probleme a cărei implementare este foarte simplă.

Obiectivele de învățare

  • Cum se codifică folosind un model de design adaptor?

Noțiuni de bază

Să creăm o listă de tranzacții din organizația Y care sunt convertite în modele pe care le solicită aplicația client a organizației X. Clasa de mai sus este cunoscută ca „Adaptat”.


 public class OrgYTransactions { public List<string> GetTransactionsList() { List<string> transactions = new List<string>(); transactions.Add("Debit 1"); transactions.Add("Debit 2"); transactions.Add("Debit 3"); return transactions; } }


În al doilea rând, să creăm o interfață țintă.


 public interface ITransactions{ List<string> GetTransactions(); }


Acum, în sfârșit, să implementăm clasa adaptorului după cum urmează.


 public class TransAdapter : OrgYTransactions, ITransactions { public List<string> GetTransactions() { return GetTransactionsList(); } }


După ce toate implementările de mai sus au fost realizate, să înțelegem cum să folosim clasa adaptorului într-o aplicație de consolă.


 class Program { static void Main(string[] args) { ITransactions adapter = new TransAdapter(); foreach (var item in adapter.GetTransactions()) { Console.WriteLine(item); } } }


Dacă vă uitați îndeaproape la utilizarea de mai jos, am folosit interfața țintă ITransactions și clasa adaptorului TransAdapter fără a lua în considerare modul în care arată interfețele din clasa terță parte OrgYTransactions. Aceasta este puterea modelului de design al adaptorului, care convertește interfețele unei clase în interfețe pe care le solicită clientul.

Model de design — Constructor

Potrivit Gang of Four, un model de creație „Builder” permite separarea și refolosirea unei anumite metode pentru a construi ceva.


Caz de utilizare

Să luăm un exemplu de mașină, iar utilizatorul a dorit să construiască două modele, adică SUV și Sedan.


Modelul de design Builder este util în cazul de utilizare de mai sus și haideți să vedem o demonstrație pas cu pas.


Clasa Car are următoarele proprietăți.

 public class Car{ public string Name { get; set; } public double TopSpeed { get; set; } public bool IsSUV { get; set; } }

Obiectivele de învățare

  • Cum se codifică folosind un model de design de constructor?

Noțiuni de bază

În primul rând, să implementăm un constructor de clasă abstractă extins cu diferite modele de mașini, cum ar fi SUV-uri sau sedanuri, conform cazului de utilizare.


 public abstract class CarBuilder { protected readonly Car _car = new Car(); public abstract void SetName(); public abstract void SetSpeed(); public abstract void SetIsSUV(); public virtual Car GetCar() => _car; }


Clasa abstractă constă din următoarele metode

  • Metode abstracte pentru fiecare proprietate a clasei Car.
  • O metodă virtuală care scoate instanța clasei Car.


Acum, să creăm o fabrică care utilizează clasa CarBuilder pentru a construi diferite modele de mașini și returnează instanța mașinii realizate.


 public class CarFactory { public Car Build(CarBuilder builder) { builder.SetName(); builder.SetSpeed(); builder.SetIsSUV(); return builder.GetCar(); } }


În cele din urmă, implementați diferite modele de mașini.

ModelSuv.cs

 public class ModelSuv : CarBuilder { public override void SetIsSUV() { _car.IsSUV = true; } public override void SetName() { _car.Name = "Maruti SUV"; } public override void SetSpeed() { _car.TopSpeed = 1000; } }

ModelSedan.cs

 public class ModelSedan : CarBuilder { public override void SetIsSUV() { _car.IsSUV = false; } public override void SetName() { _car.Name = "Maruti Sedan"; } public override void SetSpeed() { _car.TopSpeed = 2000; } }

Cum să utilizați modelul generator de utilizatori din metoda Main().

În cele din urmă, să folosim modele de design pentru a construi diferite modele de mașini cu ajutorul unei metode fabrică.Build(<model>).


 static void Main(string[] args) { var sedan = new ModelSedan(); var suv = new ModelSuv(); var factory = new CarFactory(); var builders = new List<CarBuilder> { suv, sedan }; foreach (var b in builders) { var c = factory.Build(b); Console.WriteLine($"The Car details" + $"\n--------------------------------------" + $"\nName: {c.Name}" + $"\nIs SUV: {c.IsSUV}" + $"\nTop Speed: {c.TopSpeed} mph\n"); } }

Utilizarea de mai sus arată cât de grațios putem construi diferite modele de mașini folosind modelul de design constructor.


Modelul de cod este foarte ușor de întreținut și extensibil. Dacă, în viitor, trebuie să dezvoltăm un nou model, doar noul model trebuie să extindă clasa CarBuilder și este gata.

Ieșire

Cum să utilizați modelul lanțului de responsabilitate

Potrivit Gang of Four, definește un lanț de responsabilități pentru procesarea unei cereri. Cu alte cuvinte, treceți cererea de la un obiect la altul până când un obiect își acceptă responsabilitatea.


Caz de utilizare

Să luăm în considerare un exemplu de sistem de daune în orice companie corporativă. Iată lista intervalului de preț care poate fi aprobat și de către cine.


 100–1000 Rs => Junior/Senior Engineers => Approved by Manager 1001–10000 Rs => Managers => Approved by Senior Manager


Dacă suma este în afara intervalului de 10000, este necesară aprobarea excepțională din partea managerului superior.


Cazul de utilizare de mai sus poate fi implementat cu ușurință folosind modelul de proiectare Lanț de responsabilitate. Deci, clasa de revendicare are următoarele proprietăți.


 public class Claim{ public int Id{get;set;} public double amount{get;set;} }

Noțiuni de bază

În primul rând, să definim ce funcții poate îndeplini un autorizator de revendicare și să stabilim o ierarhie pentru angajații de la diferite niveluri. Implementați o clasă abstractă, așa cum se arată mai jos


 public abstract class ClaimApprover { protected ClaimApprover claimApprover; public void SetHierarchy(ClaimApprover claimApprover) { this.claimApprover = claimApprover; } public abstract void ApproveRequest(Claim claim); }


Conform cazului de utilizare, haideți să conducem solicitantul de revendicare din clasa „junior/senior”. Observați că această clasă/desemnare de angajați nu poate aproba nicio revendicare.


 public class Junior : ClaimApprover { public override void ApproveRequest(Claim claim) { System.Console.WriteLine("Cannot approve"); } }


În mod similar, să definim implementarea pentru rolurile de Manager și Senior Manager.


 public class Manager : ClaimApprover { public override void ApproveRequest(Claim claim) { if (claim.amount >= 100 && claim.amount <= 1000) { System.Console.WriteLine($"Claim reference {claim.Id} with amount {claim.amount} is approved by Manager"); } else if (claimApprover != null) { claimApprover.ApproveRequest(claim); } } }


Observați că pe baza intervalului de sume, dacă se află în intervalul Managerului, cererea poate fi aprobată de către Manager; în caz contrar, cererea va fi transmisă Senior Managerului.


 public class SeniorManager : ClaimApprover { public override void ApproveRequest(Claim claim) { if (claim.amount > 1000 && claim.amount <= 10000) { System.Console.WriteLine($"Claim reference {claim.Id} with amount {claim.amount} is approved by Senior Manager"); } else { System.Console.WriteLine($"Exceptional approval for Claim reference {claim.Id} with amount {claim.amount} is approved by Senior Manager"); } } }


În mod similar, dacă intervalul de sume se află în intervalul Senior Manager, cererea poate fi aprobată de către Manager; în caz contrar, fiind ultimul în ierarhie, se face o aprobare excepțională pentru o sumă în afara intervalului.


 ClaimApprover junior = new Manager(); ClaimApprover sukhpinder = new Manager(); ClaimApprover singh = new SeniorManager(); junior.SetHierarchy(sukhpinder); sukhpinder.SetHierarchy(singh); Claim c1 = new Claim() { amount = 999, Id = 1001 }; Claim c2 = new Claim() { amount = 10001, Id = 1002 }; junior.ApproveRequest(c1); sukhpinder.ApproveRequest(c2);

Cum să utilizați modelul lanțului de responsabilitate?

  1. Definiți aprobarea revendicărilor: junior, deși nu poate aproba nicio revendicare.
  2. Definiți aprobarea revendicării: manager „sukhpinder”.
  3. Definiți aprobarea revendicării: managerul superior „Singh”.
  4. Stabiliți o relație de ierarhie pentru junior, adică, avizul de revendicări este managerul.
  5. Stabiliți o relație de ierarhie pentru manager, adică, aprobatorul de revendicări este managerul superior.
  6. Creați două game diferite de revendicări.
  7. Junior trimite cererea de revendicare managerului.
  8. Managerul trimite cererea de revendicare managerului superior.

Ieșire

 Claim reference 1001 with amount 999 is approved by Manager Exceptional approval for Claim reference 1002 with amount 10001 is approved by Senior Manager


Pentru ieșirea liniei 1, suma a fost în interval, așa că managerul a aprobat-o.


Pentru ieșirea din linia 2, deși managerul superior a aprobat-o, suma a fost în afara intervalului.

Model de design — Decorator

Potrivit Gang of Four, modelul adaugă responsabilități suplimentare unui obiect de clasă în mod dinamic.


Caz de utilizare

Să luăm în considerare exemplul cumpărării unei mașini în valoare de zece lakhs; compania oferă următoarele caracteristici suplimentare.

  • Trapă
  • Sistem muzical avansat
  • si multe altele


Cu unele caracteristici suplimentare, prețul total al mașinii crește. Să implementăm cazul de utilizare de mai sus folosind modelul Decorator.

Obiectivele de învățare

  • Cum se codifică folosind un model de design de decorator?

Noțiuni de bază

Să implementăm cazul de utilizare definit mai sus. În primul rând, definiți o clasă abstractă Car și metodele sale de bază.


 public abstract class Car{ public abstract int CarPrice(); public abstract string GetName(); }


Luați în considerare o mașină mică care se extinde deasupra clasei abstracte Car.


 public class SmallCar : Car{ public override int CarPrice() => 10000; public override string GetName() => "Alto Lxi"; }


Acum, implementați clasa CarDecorator folosind componenta Car.


 public class CarDecorator : Car { protected Car _car; public CarDecorator(Car car) { _car = car; } public override int CarPrice() => _car.CarPrice(); public override string GetName() =>_car.GetName(); }


Acum, să creăm o clasă separată pentru fiecare caracteristică suplimentară disponibilă pentru Car care moștenește clasa CarDecorator.


Conform cazului de utilizare, caracteristicile suplimentare sunt o trapă și un sistem muzical avansat.

AdvanceMusic.cs

Ignorați metodele ca

  • Adăugați costul suplimentar al unui „sistem muzical avansat” la prețul total al mașinii.

  • Actualizați numele mașinii cu numele caracteristicii suplimentare.

     public class AdvanceMusic : CarDecorator { public AdvanceMusic(Car car) : base(car) { } public override int CarPrice() => _car.CarPrice() + 3000; public override string GetName()=> "Alto Lxi with advance music system"; }

Trapă. cs

Ignorați metodele ca

  • Adăugați costul suplimentar al unui „trapă” la prețul total al mașinii.
  • Actualizați numele mașinii cu numele caracteristicii suplimentare.
 public class Sunroof : CarDecorator { public Sunroof(Car car) : base(car) { } public override int CarPrice() => _car.CarPrice() + 2000; public override string GetName() => "Alto Lxi with Sunroof"; }

Model de decorator în acțiune

Creați o instanță de SmallCar și afișați numele și prețul mașinii.


 Car car = new SmallCar(); Console.WriteLine($"Price of car {car.GetName()} : " + car.CarPrice());


Acum, să adăugăm funcții suplimentare, așa cum se arată mai jos


 var car1 = new Sunroof(car); var car2 = new AdvanceMusic(car);

Cod complet

 static void Main(string[] args) { Car car = new SmallCar(); Console.WriteLine($"Price of car {car.GetName()} : " + car.CarPrice()); var car1 = new Sunroof(car); Console.WriteLine($"Price of car {car1.GetName()} : " + car1.CarPrice()); var car2 = new AdvanceMusic(car); Console.WriteLine($"Price of car {car2.GetName()} : " + car2.CarPrice()); }

Ieșire

Felicitări..!! Ați implementat cu succes cazul de utilizare folosind modelul decorator.

Model de proiectare — Metoda fabricii

Conform Gang of Four, metoda din fabrică permite subclasei să determine ce obiect de clasă trebuie creat.


Obiectivele de învățare

  • Care este modelul de proiectare a metodei din fabrică?
  • Cum se scrie cod folosind metoda din fabrică?

Noțiuni de bază

Să luăm în considerare un exemplu de orice bancă cu tipuri de conturi ca de economii și conturi curente. Acum, să implementăm exemplul de mai sus folosind modelul de proiectare din fabrică


În primul rând, creați o clasă abstractă de tip cont.


 public abstract class AccoutType { public string Balance { get; set; } }


Implementați clasele de cont curente și de salvare moștenind clasa abstractă AccountType, așa cum se arată mai jos.


 public class SavingsAccount : AccoutType { public SavingsAccount() { Balance = "10000 Rs"; } } public class CurrentAccount : AccoutType { public CurrentAccount() { Balance = "20000 Rs"; } }


În cele din urmă, să implementăm interfața din fabrică, care va oferi un contract care ajută la crearea unui obiect de clasă. Această interfață este cunoscută și sub numele de Creator.


 public interface IAccountFactory { AccoutType GetAccoutType(string accountName); }


În cele din urmă, scrieți o implementare a metodei interfeței creatorului, așa cum se arată mai jos. Clasa care implementează creatorul este cunoscută sub numele de Creator de beton.


 public class AccountFactory : IAccountFactory { public AccoutType GetAccoutType(string accountName) { if (accountName.Equals("SAVINGS", StringComparison.OrdinalIgnoreCase)) { return new SavingsAccount(); } else if (accountName.Equals("CURRENT", StringComparison.OrdinalIgnoreCase)) { return new CurrentAccount(); } else { throw new ArgumentException("Invalid account name"); } } }


Asta este. Ați implementat cu succes metoda din fabrică folosind exemplul Bank.

Cum să utilizați metoda din fabrică?

O subclasă va decide ce obiect de clasă „AccountType” va fi creat pe baza numelui contului.


 class Program { static void Main(string[] args) { IAccountFactory accountFactory = new AccountFactory(); var savingAccount = accountFactory.GetAccoutType("SAVINGS"); Console.WriteLine("Saving account balance: " + savingAccount.Balance); var currentAccount = accountFactory.GetAccoutType("CURRENT"); Console.WriteLine("Current account balance: " + currentAccount.Balance); } }

De exemplu, dacă numele contului este „SAVINGS”, atunci obiectul clasei „SavingAccount” va fi creat și returnat.


În mod similar, dacă numele contului este „CURRENT”, atunci obiectul clasei „CurrentAccount” va fi instanțiat și returnat.

Ieșire

 Saving account balance: 10000 Rs Current account balance: 20000 Rs

Model de proiectare — Iterator

Potrivit Gang of Four, modelul iterator oferă un proces pentru a obține obiectul agregator fără a cunoaște implementarea acestuia.


Caz de utilizare

Să luăm un exemplu de listă de colecție de mașini și string[] o matrice de motociclete, trebuie să proiectăm un obiect agregator astfel încât să se poată itera peste colecție fără a ști dacă este o listă sau o matrice.


Modelul de proiectare a iteratorului ajută la rezolvarea acestei probleme în care un iterator standard va traversa diferite tipuri de colecție.

Noțiuni de bază

Având în vedere cazul de utilizare de mai sus, să definim o interfață de iterator personalizată care acționează ca un strat abstract peste iteratorul de listă și matrice.


 public interface IVehicleIterator{ void First(); bool IsDone(); string Next(); string Current(); }


Acum, scrieți iteratoare pentru mașini și motociclete care implementează interfața de mai sus în funcție de cazul de utilizare.

CarIterator.cs

 public class CarIterator : IVehicleIterator { private List<string> _cars; private int _current; public CarIterator(List<string> cars) { _cars = cars; _current = 0; } public string Current() { return _cars.ElementAt(_current); } public void First() { _current = 0; } public bool IsDone() { return _current >= _cars.Count; } public string Next() { return _cars.ElementAt(_current++); } }


Iteratorul auto este implementat peste colecția List<string> și oferă o implementare a metodelor de interfață.

MotorcycleIterator.cs

Iteratorul motocicletei este implementat peste colecția string[] și oferă o implementare a metodelor de interfață.


 public class MotercycleIterator : IVehicleIterator { private string[] _motercylces; private int _current; public MotercycleIterator(string[] motercylces) { _motercylces = motercylces; _current = 0; } public string Current() { return _motercylces[_current]; } public void First() { _current = 0; } public bool IsDone() { return _current >= _motercylces.Length; } public string Next() { return _motercylces[_current++]; } }


După ce toți iteratorii de mai sus sunt definiți, definiți o interfață standard de obiect agregator care creează iteratoare.


 public interface IVehicleAggregate{ IVehicleIterator CreateIterator(); }


În cele din urmă, notați clasele care implementează interfața de agregare de mai sus. Conform cazului de utilizare, ambele clase de mașini și motociclete vor implementa interfața de agregare.

masina. cs

Metoda interfeței agregatorului returnează iteratorul relevant, așa cum se arată mai jos.


 public class Car : IVehicleAggregate { private List<string> _cars; public Car() { _cars = new List<string> { "Car 1", "Car 2", "Car 3" }; } public IVehicleIterator CreateIterator() { return new CarIterator(_cars); } }

Motocicletă. cs

Metoda interfeței agregatorului returnează iteratorul relevant, așa cum se arată mai jos.


 public class Motercycle : IVehicleAggregate { private string[] _motercycles; public Motercycle() { _motercycles = new[] { "Bike 1", "Bike 2", "Bike 3" }; } public IVehicleIterator CreateIterator() { return new MotercycleIterator(_motercycles); } }

Model iterator în acțiune

Metodele PrintVehicles verifică dacă !iterator.isDone apoi scoate elementul de colecție. Indiferent de ce colecție avem de-a face, implementați metode precum First, IsDone și Next.


 static void Main(string[] args) { IVehicleAggregate car = new Vehicles.Car(); IVehicleAggregate motercycle = new Vehicles.Motercycle(); IVehicleIterator carIterator = car.CreateIterator(); IVehicleIterator motercycleIterator = motercycle.CreateIterator(); PrintVehicles(carIterator); PrintVehicles(motercycleIterator); } static void PrintVehicles(IVehicleIterator iterator) { iterator.First(); while (!iterator.IsDone()) { Console.WriteLine(iterator.Next()); } }

Ieșire

Nu cunoaștem tipul de colecție de bază, dar este încă repetat prin modelul de proiectare Iterator. Dacă mergeți mai departe și rulați, afișează următoarea ieșire.

Design Pattern — Mediator

Potrivit Gang of Four, modelul Mediator încapsulează interacțiunea obiectului unul cu celălalt.


Modelul de design al mediatorului ne ajută să proiectăm aplicații slab cuplate prin încapsularea interacțiunilor obiectelor.

Caz de utilizare

Să luăm în considerare un exemplu de cameră de chat în care participanții se înregistrează și cum să comunice eficient.


Trebuie să implementați următoarea conversație de chat folosind modelul de design Mediator.


 David to Scott: 'Hey' Scott to David: 'I am good how about you.' Jennifer to Ashley: 'Hey ashley... david is back in the group' Jennifer to David: 'Where have you been?' Ashley to David: 'How come you aren't active here anymore?'

Obiectivele de învățare

  • Cum se codifică folosind un model de design mediator?

Noțiuni de bază

Pasul principal este de a crea o listă de nume de utilizator care vor fi folosite în interiorul unei camere de chat. O enumerare publică pentru aceasta este afișată mai jos.


 public enum Username{ Ashley, David, Jennifer, Scott }


Acum, în primul rând, implementați un strat abstract al camerei de chat.


 public abstract class AChatroom { public abstract void Register(User user); public abstract void Post(string fromUser, string toUser, string msg); }


Și o clasă care definește metode abstracte. Metodele validează dacă utilizatorul există în dicționar. De exemplu, metoda de înregistrare validează dacă utilizatorul există deja sau nu. Dacă nu există, atunci înregistrați utilizatorul doar în camera de chat.


 public class Chatroom : AChatroom { private Dictionary<string, User> _users = new Dictionary<string, User>(); public override void Post(string fromUser, string toUser, string msg) { User participant = _users[toUser]; if (participant != null) { participant.DM(fromUser, msg); } } public override void Register(User user) { if (!_users.ContainsValue(user)) { _users[user.Name] = user; } user.Chatroom = this; } }


În cele din urmă, să implementăm acțiunile pe care utilizatorul le poate efectua, cum ar fi postarea unui mesaj către un utilizator în camera de chat sau primirea unui DM de la alt utilizator.


 public class User { private Chatroom _chatroom; private string _name; public User(string name) => this._name = name; public string Name => _name; public Chatroom Chatroom { set { _chatroom = value; } get => _chatroom; } public void Post(string to, string message) => _chatroom.Post(_name, to, message); public virtual void DM(string from, string message) => Console.WriteLine("{0} to {1}: '{2}'", from, Name, message); }

Cum să utilizați modelul mediator din metoda principală

 static void Main(string[] args) { Chatroom chatroom = new Chatroom(); User Jennifer = new UserPersona(Username.Jennifer.ToString()); User Ashley = new UserPersona(Username.Ashley.ToString()); User David = new UserPersona(Username.David.ToString()); User Scott = new UserPersona(Username.Scott.ToString()); chatroom.Register(Jennifer); chatroom.Register(Ashley); chatroom.Register(David); chatroom.Register(Scott); David.Post(Username.Scott.ToString(), "Hey"); Scott.Post(Username.David.ToString(), "I am good how about you."); Jennifer.Post(Username.Ashley.ToString(), "Hey ashley... david is back in the group"); Jennifer.Post(Username.David.ToString(), "Where have you been?"); Ashley.Post(Username.David.ToString(), "How come you aren't active here anymore?"); Console.ReadKey(); }


  1. Este creat obiectul clasei Chatroom.
  2. Patru utilizatori diferiți sunt creați cu nume unice.
  3. Înregistrați-i pe fiecare în camera de chat.
  4. Utilizatorii pot începe acum să posteze mesaje unul altuia.

Execuția programului descrie doar metoda Post a clasei de utilizator.


Ieșire: Istoricul camerei de chat al execuției programului de mai sus


 David to Scott: 'Hey' Scott to David: 'I am good how about you.' Jennifer to Ashley: 'Hey ashley... david is back in the group' Jennifer to David: 'Where have you been?' Ashley to David: 'How come you aren't active here anymore?'

Model de design — Observator

Conform Gang of Four, modelul observatorului definește dependența între două sau mai multe obiecte. Deci, atunci când starea unui obiect se schimbă, atunci toți dependenții lui sunt notificați.


Cu alte cuvinte, o modificare a unui obiect inițiază notificarea într-un alt obiect.

Caz de utilizare

Să luăm un exemplu de influență de celebritate Instagram care are un număr „ x ” de urmăritori. Deci, în momentul în care celebritatea adaugă o postare, atunci toți urmăritorii sunt anunțați.


Să implementăm cazul de utilizare menționat anterior folosind modelul de proiectare Observer.

Obiectivele de învățare

  • Cum se codifică folosind un model de design observator?

Noțiuni de bază

Conform cazului de utilizare, primul implementează o interfață care conține ce acțiuni poate efectua o celebritate. Este cunoscut ca „ Subiect ”.


 public interface ICelebrityInstagram{ string FullName { get; } string Post { get; set; } void Notify(string post); void AddFollower(IFollower fan); void RemoveFollower(IFollower fan); }

Subiectul conține următoarele funcții de membru.

  • Notificare: Pentru a notifica toți adepții.

  • AddFollower: Adăugați un nou urmăritor la lista de celebrități.

  • RemoveFollower: Eliminați un urmăritor din lista de celebrități.


Acum, implementați interfața de observator „IFollower”, care conține funcția de membru „Actualizare” pentru notificare.


 public interface IFollower{ void Update(ICelebrityInstagram celebrityInstagram); }


În cele din urmă, este timpul să implementăm „Implementare concretă” atât pentru „ Subiect ”, cât și pentru „ Observator ”.

ConcreteObserver numit „Follower.cs”

Oferă o implementare a funcției de membru Actualizare, care trimite numele celebrității și postarea pe consolă.


 public class Follower : IFollower { public void Update(ICelebrityInstagram celebrityInstagram) { Console.WriteLine($"Follower notified. Post of {celebrityInstagram.FullName}: " + $"{celebrityInstagram.Post}"); } }

Subiect concret numit „Sukhpinder. cs”

 public class Sukhpinder : ICelebrityInstagram { private readonly List<IFollower> _posts = new List<IFollower>(); private string _post; public string FullName => "Sukhpinder Singh"; public string Post { get { return _post; } set { Notify(value); } } public void AddFollower(IFollower follower) { _posts.Add(follower); } public void Notify(string post) { _post = post; foreach (var item in _posts) { item.Update(this); } } public void RemoveFollower(IFollower follower) { _posts.Remove(follower); } }

Cum să creați un model de observator?

Următorul caz de utilizare arată că ori de câte ori instrucțiunea de mai jos este executatăsukhpinder.Post = „Îmi plac modelele de design.”; Metoda de actualizare este declanșată pentru fiecare urmăritor, adică fiecare obiect de urmăritor este notificat cu privire la o nouă postare de la „Sukhpinder”.


 static void Main(string[] args) { var sukhpinder = new Sukhpinder(); var firstFan = new Follower(); var secondFan = new Follower(); sukhpinder.AddFollower(firstFan); sukhpinder.AddFollower(secondFan); sukhpinder.Post = "I love design patterns."; Console.Read(); }

Ieșire

Advance Property Pattern C# 8.0

Articolul descrie modul în care potrivirea modelelor oferă o modalitate eficientă de utilizare și procesare a acestor date în formulare care nu făceau parte din sistemul primar.


Să începem

Să luăm un exemplu de Calculator de taxă și să vedem cum potrivirea modelelor ajută la scrierea unui algoritm pentru asta.

Clasa de entitate utilizată pe tot parcursul articolului

 public class Car { public int PassengerCount { get; set; } } public class DeliveryTruck { public int Weight { get; set; } } public class Taxi { public int Fare { get; set; } } public class Bus { public int Capacity { get; set; } public int RidersCount { get; set; } }


Exemplul 1: Calculați tariful de taxare conform următoarelor condiții:


  • Dacă vehiculul este mașină => 100 Rs
  • Dacă vehiculul este DeliveryTruck => 200 Rs
  • Dacă vehiculul este Autobuz => 150 Rs
  • Dacă vehiculul este un taxi => 120 Rs

Program de potrivire a modelelor cu noua sintaxă de comutare

Dacă tipul de vehicul se potrivește cu Car 100 este returnat și așa mai departe. Observați că null și {} sunt cazuri implicite pentru tipul de obiect.

De asemenea, „_” poate fi folosit pentru a programa scenariul implicit. Consultați noua sintaxă a comutatorului.


Este o modalitate mult mai curată și mai eficientă de codare și, de asemenea, a recomandat utilizarea numelor de variabile cu o singură literă în sintaxa comutatorului.


 public static int TollFare(Object vehicleType) => vehicleType switch { Car c => 100, DeliveryTruck d => 200, Bus b => 150, Taxi t => 120, null => 0, { } => 0 };

Testați deasupra programului

Exemple de testare din punct de vedere al aplicației consolă. Codul de mai jos ilustrează cum să apelați funcția de potrivire a modelelor de mai sus din metoda principală.


 var car = new Car(); var taxi = new Taxi(); var bus = new Bus(); var truck = new DeliveryTruck(); Console.WriteLine($"The toll for a car is {TollFare(car)}"); Console.WriteLine($"The toll for a taxi is {TollFare(taxi)}"); Console.WriteLine($"The toll for a bus is {TollFare(bus)}"); Console.WriteLine($"The toll for a truck is {TollFare(truck)}");

Ieșire consolă

 The toll for a car is 100 The toll for a taxi is 120 The toll for a bus is 150 The toll for a truck is 200


Exemplul 2: adăugați prețul de ocupare în funcție de tipul de vehicul


  • Mașinile și taxiurile cu pasageri „NU” plătesc 10 Rs.
  • Mașinile și taxiurile cu doi pasageri beneficiază de o reducere de 10 lei.
  • Mașinile și taxiurile cu trei sau mai mulți pasageri beneficiază de o reducere de 20 de lei.
  • Autobuzele care reprezintă mai puțin de 50% din pasageri plătesc 30 de lei în plus.
  • Autobuzele care au mai mult de 90% din pasageri beneficiază de o reducere de 40 de lei.
  • Camioanele de peste 5000 lbs sunt taxate cu 100 Rs.
  • Camioane ușoare sub 3000 lbs, cu o reducere de 20 Rs.

Comutator de potrivire a modelului

Consultați sintaxa de potrivire a modelelor cu clase de proprietăți unice și multiple. Legătură

Potrivirea modelelor — Entitate auto

 Car { PassengerCount: 0 } => 100 + 10, Car { PassengerCount: 1 } => 100, Car { PassengerCount: 2 } => 100 - 10, Car c => 100 - 20,

Potrivirea modelelor — Entitate taxi

 Taxi {Fare:0 }=>100+10, Taxi { Fare: 1 } => 100, Taxi { Fare: 2 } => 100 - 10, Taxi t => 100 - 20,

Potrivirea modelului — Entitate autobuz

 Bus b when ((double)b.RidersCount / (double)b.Capacity) < 0.50 => 150 + 30, Bus b when ((double)b.RidersCount / (double)b.Capacity) > 0.90 => 150 - 40, Bus b => 150,

Potrivirea modelelor — Entitatea de camion de livrare

 DeliveryTruck t when (t.Weight > 5000) => 200 + 100, DeliveryTruck t when (t.Weight < 3000) => 200 - 20, DeliveryTruck t => 200,

Combinarea tuturor entităților

Exemplul de mai jos evidențiază avantajele potrivirii modelelor: ramurile modelului sunt compilate în ordine. Compilatorul avertizează și despre codul inaccesibil.


 public static int OccupancyTypeTollFare(Object vehicleType) => vehicleType switch { Car { PassengerCount: 0 } => 100 + 10, Car { PassengerCount: 1 } => 100, Car { PassengerCount: 2 } => 100 - 10, Car c => 100 - 20, Taxi { Fare: 0 } => 100 + 10, Taxi { Fare: 1 } => 100, Taxi { Fare: 2 } => 100 - 10, Taxi t => 100 - 20, Bus b when ((double)b.RidersCount / (double)b.Capacity) < 0.50 => 150 + 30, Bus b when ((double)b.RidersCount / (double)b.Capacity) > 0.90 => 150 - 40, Bus b => 150, DeliveryTruck t when (t.Weight > 5000) => 200 + 100, DeliveryTruck t when (t.Weight < 3000) => 200 - 20, DeliveryTruck t => 200, null => 0, { } => 0, };

Testați deasupra programului

Exemple de testare din punct de vedere al aplicației consolă. Codul de mai jos ilustrează cum să apelați funcția de potrivire a modelelor de mai sus din metoda principală.


 var car1 = new Car{ PassengerCount=2}; var taxi1 = new Taxi { Fare = 0 }; var bus1 = new Bus { Capacity = 100, RidersCount = 30 }; var truck1 = new DeliveryTruck { Weight = 30000 }; Console.WriteLine($"The toll for a car is {OccupancyTypeTollFare(car1)}"); Console.WriteLine($"The toll for a taxi is {OccupancyTypeTollFare(taxi1)}"); Console.WriteLine($"The toll for a bus is {OccupancyTypeTollFare(bus1)}"); Console.WriteLine($"The toll for a truck is {OccupancyTypeTollFare(truck1)}");

Ieșire consolă

 The toll for a car is 90 The toll for a taxi is 110 The toll for a bus is 180 The toll for a truck is 300


„Potrivirea modelelor face codul mai ușor de citit și oferă o alternativă la tehnicile orientate pe obiecte atunci când nu puteți adăuga cod la cursuri.”

Model de design — Singleton

Gang of Four — Modelul de design Singleton asigură că o anumită clasă are o singură instanță/obiect și un punct de acces global.


Obiectivele de învățare

  • Cum se codifică folosind un model de design singleton?

Noțiuni de bază

Clasele Singleton sunt folosite pentru a elimina instanțiarea mai multor obiecte dintr-o anumită clasă.


 public class SingletonExample { private string Name { get; set; } = "Hello from singleton"; private static SingletonExample _instance; public static SingletonExample Instance { get { if (_instance == null) { _instance = new SingletonExample(); } return _instance; } } public SingletonExample() { } public string GetName() => Name; }

Dărâma

  1. Iterația 1 _instance==null înseamnă că vor fi create numai instanțe.
  2. Iterația 2, ca acum _intance !=null Deci instanțe create anterior vor fi returnate.

Testați folosind o aplicație de consolă

Să apelăm de două ori clasa singleton și să atribuim instanța returnată la două variabile diferite. În cele din urmă, verificați dacă ambele obiecte sunt egale folosind funcțiaObject.Equals.


 static void Main(string[] args) { var response = SingletonExample.Instance; Console.WriteLine(response); var response1 = SingletonExample.Instance; Console.WriteLine(response1); Console.WriteLine(Object.Equals(response1, response)); }
  • Dacă returnează adevărat, înseamnă că este produsă o singură instanță de fiecare dată.
  • Dacă returnează false, înseamnă că clasa nu urmează modelul singleton.

Ieșire

Ieșirea consolei returnează true; Felicitări. Ați implementat cu succes modelul Singleton.



Siguranța firelor

Clasa de mai sus este cunoscută ca clasa singleton, dar în prezent, nu este sigură pentru fire. Într-un mediu cu mai multe fire, două fire pot atinge instrucțiunea if (_instance == null) în același timp și vom ajunge să avem mai multe instanțe ale unei clase singleton.


O modalitate pentru un fir mai sigur este folosirea unui mecanism de blocare, iar cealaltă modalitate este de a crea o instanță de numai citire pentru o abordare mai curată și mai eficientă.

 public class ThreadSafeSingleton { private static readonly ThreadSafeSingleton _instance = new ThreadSafeSingleton(); public static ThreadSafeSingleton Instance { get { return _instance; } } public ThreadSafeSingleton() { } }

Eșantion Github

https://github.com/ssukhpinder/DesignPatterns

Vă mulțumim pentru citit!

Sponsorizările mă ajută să continui să mențin și să construiesc noi proiecte ca acestea.


🙏 Dacă utilizați Pay, Noticed sau oricare dintre celelalte proiecte ale mele, o mică contribuție ar însemna MULT. Pe cont propriu, open-source nu plătește facturile. Sper că, cu ajutorul tău, să-mi continui munca poate fi sustenabilă și nu va trebui să merg să-mi iau un loc de muncă adevărat 😛.

Programare C#🚀

Vă mulțumim că faceți parte din comunitatea C#!

Cumpără cafea