64x64
Granit Rexha
Software engineer. Loves to write.
15 Qershor 2018 · 12 min lexim

Modelet e projektimit softuerik në C#, të shpjeguara thjesht, pjesa 1

Modelet e projektimit softuerik në C#, të shpjeguara thjesht, pjesa 1

Modelet e projektimit (Design patterns) janë zgjidhje për problemet të cilat përseriten; udhëzimet për të trajtuar probleme specifike të cilat shfaqen në zhvillimin e softuerëve. Ato nuk janë klasa, paketa apo librari te cilat mund t'i inkuadroni në aplikacionet tuaja dhe të prisni që të ndodh magjia, por më tepër janë udhëzime si ti qaseni probleme të cilat përsëriten gjatë dizajnimit të softuerëve.


Wikipedia thotë:

Në inxhinerinë softuerike, një model i projektimit është një zgjidhje gjenerale e ripërdorshme për një kontekst specifik në dizajnimin e softuerëve. Nuk është një dizajn përfundimtar që mund të transformohet drejtëpërdrejtë në kod. Është një përshkrues apo shabllon se si të zgjidhim një problem që mund të përdoret në situata të ndryshme.


Mbani në mend:


  • Modelet e projektimit nuk janë zgjidhje magjike për të gjitha problemet
  • Mos u mundoni t'i përdorni me forcë në të gjitha situatat, sepse kjo mund të ndikojë negativisht në aplikacionet tuaja. Keni parasysh që modelet e projektimit janë zgjidhje e problemeve e jo zgjidhjet për të gjetur probleme.
  • Nëse përdoren në vendin e duhur dhe në mënyrë e duhur, mund të jënë shpëtimtarë të vërtetë, në të kundërtën mund të rezultojnë në rrëmujë të vërtëtë të kodit.


Kemi tre lloje te modeleve të projektimit:

1. Modelet krijuese

2. Modelet strukturore

3. Modelet e sjelljeve


Për secilin prej tyre do të dedikojmë nga një postim të veqantë. Në këtë artikull do të fukosohemi në modelet krijuese.


Modelet krijuese


Me fjalë të thjeshta modelet krijuese janë modelet e projektimit të cilat janë të fokusuara në mënyrën e krijimit apo inicializimit të një objekti apo një grupi të objekteve.


Nga Wkipedia kemi:

Në inxhinierinë softuerike modelet krijuese merren me mekanizmat e krijimit të objekteve, duke u munduar të krijojnë objekte në mënyrë sa më të përshtatshme për situatën e dhënë. Forma bazike e krijimit të objekteve mund të rezultojë në probleme të dizajnimit apo të shtojë kompleksitete në arkitekturën e softuerit. Modelet krijuese e zgjidhin këtë problem duke e kontrolluar disi krijimin e objekteve.


Disa nga modelet kryesore krijuese janë:

  • Simple factory
  • Factory method
  • Abstract factory
  • Builder
  • Prototype
  • Singleton


*Për shkak se mungojnë përkthimet adekuatë për disa nga emrat e modeleve të projektimit atëherë kam vendosur që emrat e këtyre modeleve t'i lë në gjuhën angleze, që të kutpohen më lehtë, si dhe të ju mundësojë fillestarëve që të gjejnë më lehtë informacione shtesë rreth këtyre modeleve. Poashtu edhe shembujt programatik te ketyre modeleve jane ne gjuhen angleze. Shpresoj ne miekuptimin tuaj.


Simple factory


Shembull nga jeta e përditshme:

Paramendoni se jeni duke ndërtuar një shtëpi dhe ju duhen dyert. Do të ishte rremujë në qoftë se cdo herë që ju duhet një derë, ju filloni ta ndërtoni atë vetë.


Me fjatë të thjeshta:

Simple factory gjeneron një instancë të një objekti pa e ekspozuar logjikën e inicializimit tek klienti.


Wikipedia thotë:

Në programimin e orientuar në objekte (OOP), një prodhues është një objekt që krijon objekte të tjera - formalisht, një prodhues është një metodë apo funksion që kthen një objekt të një klase të caktuar nga ndonjë thirrje e metodës, e cila supozohet të fillojë me "new".


Shembull programatik:

Së pari kemi interface-n dhe implementimin

public interface IDoor
{
    int GetHeight();
    int GetWidth();
}

public class WoodenDoor : IDoor
{
    private int Height { get; set; }
    private int Width { get; set; }

    public WoodenDoor(int height, int width)
    {
        this.Height = height;
        this.Width = width;
    }

    public int GetHeight()
    {
        return this.Height;
    }
    public int GetWidth()
    {
        return this.Width;
    }
}

Më pas kemi prodhuesit tonë të derës i cili e krijon derën dhe e kthen atë:

public static class DoorFactory
{
    public static IDoor MakeDoor(int height, int width)
    {
        return new WoodenDoor(height, width);
    }
}

Dhe mund te përdoret si

var door = DoorFactory.MakeDoor(80, 30);
Console.WriteLine("Height of Door : {0}", door.GetHeight());
Console.WriteLine("Width of Door : {0}", door.GetWidth());


Kur të përdoret?

Kur krijimi i një objekti nuk është i thjeshtë dhe përmban logjikë të caktuar, është më e përshtatshme të vendoset në një fabrikë sesa të përsëritet kodi i njejtë në shumë vende.


Factory method


Shembull nga jeta e përditshme:

Imagjinoni rastin e një rekrutuesi. Është e pamundur që një person të intervistojë për të gjithë pozitat. Bazuar në pozitën e caktuar, ai/ajo duhet të vendosë dhe të delegojë hapat e caktuara të intervistimit tek personat e caktuar.


Me fjalë të thjeshta:

Ofron një mënyrë të delegimit të logjikës së inicializimit tek klasat fëmijë.


Wikipedia thotë:

Ne programimin e bazuar në klasa, factory-method është një model krijues që përdorë metodat e krijimit për tu ballafaquar me problemin e krijimit të objekteve pa specifikuar klasën e saktë të objektit që do të krijohet. Kjo arrihet përmes krijimit të objekteve duke përdorur factory-method të cilat janë të specifikuara në një interface dhe të implementuar nga klasat fëmijë, apo të implementuara në një klase prind dhe më pas opsionalisht të mbishkruara nga ndonjë prej klasëve fëmijë.


Shembull programatik:
interface IInterviewer
{
    void AskQuestions();
}

class Developer : IInterviewer
{
    public void AskQuestions()
    {
        Console.WriteLine("Asking about design patterns!");
    }
}

class CommunityExecutive : IInterviewer
{
    public void AskQuestions()
    {
        Console.WriteLine("Asking about community building!");
    }
}

Tani krijojme HiringManager

abstract class HiringManager
{
    // Factory method
    abstract protected IInterviewer MakeInterviewer();
    public void TakeInterview()
    {
        var interviewer = this.MakeInterviewer();
        interviewer.AskQuestions();
    }
}

Tani secila klase femije mund ta derivoje ate dhe te ofroje intervistuesin e nevojshem

class DevelopmentManager : HiringManager
{
    protected override IInterviewer MakeInterviewer()
    {
        return new Developer();
    }
}

class MarketingManager : HiringManager
{
    protected override IInterviewer MakeInterviewer()
    {
        return new CommunityExecutive();
    }
}

përdorimi

var devManager = new DevelopmentManager();
devManager.TakeInterview(); //Output : Asking about design patterns!

var marketingManager = new MarketingManager();
marketingManager.TakeInterview();


Kur të përdoret: e dobishme kur ka ndonjë procesim gjeneral në një klasë por klasa fëmijë e nevojshme përcaktohet në mënyrë dinamike gjatë ekzekutimit të kodit. Apo thënë me fjalë të tjera, kur klienti nuk e din saktësisht për cilën klase fëmijë mund të ketë nevojë.


Abstract Factory


Shembull nga jeta e përditshme: 

Le të zgjerojmë shembullin tonë të krijimit të derës nga Simple Factory. Bazuar në nevojat tuaja ju mund të bleni një derë të drurit nga dyqani i deyrve të drurit, një derë të hekurt nga dyqani i dyerve të hekurt apo një derë të plastikës nga dyqani i dyerve të plastikës. Përveq kësaj ju mund të keni nevojë për një person që ka specializime të ndryshme për të vendosur derën, për shembull një zdrukthtar për derën e drurit, një metal punues për derën e hekurt etj. Siq po e shihni kemi nje varshmëri ndërmjet dyerve, zdrukthtari për derën e drurit, metal-punuesi për derën e hekurt...


Me fjalë të thjeshta:

Një prodhues i prodhuesve, një prodhues që i bashkon objektet individuale por të ngjajshme apo të varuara me njëra tjetrën pa i specifikuar klasat e tyre konkrete.


Wikipedia thotë:

Modeli krijues abstract-factory ofron një mënyrë për të enkapsuluar një grup të prodhuesve individual që kanë një veti të përbashkët pa i specifikuar klasat e tyre konkrete.


Shembull programatik:

Duke e përdorur shembullin e derës së pari kemi interface-in e derës dhe disa nga implementimet e tij

interface IDoor {

  void GetDescription();

}
class WoodenDoor : IDoor
{
  public void GetDescription()
  {
    Console.WriteLine("I am a wooden door");
  }
}

class IronDoor : IDoor
{
  public void GetDescription()
  {
    Console.WriteLine("I am a iron door");
  }
}

Më pas kemi nga një specialist për cdo derë:

interface IDoorFittingExpert
{
  void GetDescription();
}

class Welder : IDoorFittingExpert
{
  public void GetDescription()
  {
    Console.WriteLine("I can only fit iron doors");
  }
}

class Carpenter : IDoorFittingExpert
{
  public void GetDescription()
  {
    Console.WriteLine("I can only fit wooden doors");
  }
}

Tani kemi një prodhues abstrakt i cili mund të na krijojë një familje të objekteve të ngjajshme, p.sh: prodhuesi dyerve të drurit do të na krijojë një derë të drurit dhe një specialist të drurit, prodhuesi i hekurt do të na krijojë një derë të hekurt dhe një specialist të hekurt.

interface IDoorFactory {
  IDoor MakeDoor();
  IDoorFittingExpert MakeFittingExpert();
}

// Wooden factory to return carpenter and wooden door
class WoodenDoorFactory : IDoorFactory
{
  public IDoor MakeDoor()
  {
    return new WoodenDoor();
  }

  public IDoorFittingExpert MakeFittingExpert()
  {
    return new Carpenter();
  }
}

// Iron door factory to get iron door and the relevant fitting expert
class IronDoorFactory : IDoorFactory
{
  public IDoor MakeDoor()
  {
    return new IronDoor();
  }

  public IDoorFittingExpert MakeFittingExpert()
  {
    return new Welder();
  }
}

Dhe më pas mund të përdoret sikurse në vijim:

var woodenDoorFactory = new WoodenDoorFactory();

var woodenDoor = woodenDoorFactory.MakeDoor();
var woodenDoorFittingExpert = woodenDoorFactory.MakeFittingExpert();

woodenDoor.GetDescription(); //Output : I am a wooden door
woodenDoorFittingExpert.GetDescription();//Output : I can only fit woooden doors

var ironDoorFactory = new IronDoorFactory();

var ironDoor = ironDoorFactory.MakeDoor();
var ironDoorFittingExpert = ironDoorFactory.MakeFittingExpert();

ironDoor.GetDescription();//Output : I am a iron door
ironDoorFittingExpert.GetDescription();//Output : I can only fit iron doors


Kur të përdoret: Kur kemi varshmëri të ndërlidhura me logjikë komplekse të inicializimit.


Builder


Shembull nga jeta e përditshme: 

Imagjinoni sikurse jeni në Mc Donald's dhe porositni një ofertë të caktuar, le të themi një Big Mac Menu, dhe ata ju ofrojnë porosinë pa bërë ndonjë pyetje. Ky është një shembull i simple-factory. Por, ka raste kur logjika e inicializimit mund të përfshijë më shume hapa. Për shembull ju dëshironi një menu të veqantë, dhe keni disa opsione të ndryshme, lloji i mishit, lloji i sallatës, lloji i pijes etj. Në këto raste modeli builder është zgjidhja.


Me fjalë të thjeshta:

Ju lejon të krijoni lloje të ndryshme të një objekti duke ju shmangur kompleksitetit të konstruktorit. E dobishme kur kemi lloje të ndryshme të një objekti. Ose kur përfshihen shume hapa për krijimin e një objekti.


Wikipedia thotë:

Modeli builder është nje model i dizajnimit të softuerit për krijimin e objekteve me qëllim të gjetjes së një zgjidhje për anti-modelin e konstruktorit.


Për të qenë më të qartë le të marrim një shembull se si duket një anti-model i konstruktorit:

public Burger(int size, bool cheese, bool pepperoni, bool lettuce, bool tomato)
{
}

Siq e shihni numri i parametrave të cilat i pranon konstrutori shumë shpejt mund të bëhet i pakontrollueshëm dhe mund të bëhet i vështirë për t'u kuptuar rradhitja e parametrave. Poashtu kjo listë e parametrave mund të zgjerohet nesë ju do të shtoni më shume veqori në të ardhmen. Kjo quhet anti-modeli i konstruktorit.


Shembull programatik:
class Burger
{
  private int mSize;
  private bool mCheese;
  private bool mPepperoni;
  private bool mLettuce;
  private bool mTomato;

  public Burger(BurgerBuilder builder)
  {
    this.mSize = builder.Size;
    this.mCheese = builder.Cheese;
    this.mPepperoni = builder.Pepperoni;
    this.mLettuce = builder.Lettuce;
    this.mTomato = builder.Tomato;
  }

  public string GetDescription()
  {
    var sb = new StringBuilder();
    sb.Append(String.Format("This is {0} inch Burger. ", this.mSize));
    return sb.ToString();
  }
}

Dhe më pas kemi klasën Builder

class BurgerBuilder {
  public int Size;
  public bool Cheese;
  public bool Pepperoni;
  public bool Lettuce;
  public bool Tomato;

  public BurgerBuilder(int size)
  {
    this.Size = size;
  }

  public BurgerBuilder AddCheese()
  {
    this.Cheese = true;
    return this;
  }

  public BurgerBuilder AddPepperoni()
  {
    this.Pepperoni = true;
    return this;
  }

  public BurgerBuilder AddLettuce()
  {
    this.Lettuce = true;
    return this;
  }

  public BurgerBuilder AddTomato()
  {
    this.Tomato = true;
    return this;
  }

  public Burger Build()
  {
    return new Burger(this);
  }
}

Dhe më pas mund të përdoret sikurse

var burger = new BurgerBuilder(4).AddCheese()
                                .AddPepperoni()
                                .AddLettuce()
                                .AddTomato()
                                .Build();
Console.WriteLine(burger.GetDescription());


Kur të përdoret?

Kur kemi disa lloje të një objekti dhe për t'ju shmangur përdorimit të konstruktorëve. Dallimi kryesor më modelin factory qëndron tek ajo se factory modelet përdoren kur krijimi i një objekti bëhet vetëm me një hap, ndërsa builder përdoret kur krijimi i një objekti përfshin disa hapa.


Prototype


Shembull nga jeta e përditshme:

Këni dëgjuar ndonjëherë për Dolly-n? Delja e cila ishte klonuar! Nuk po hyjmë në detaje por poenta është që modeli Prototype ka të bëjë tërësisht me klonimin.


Më fjalë të thjeshta: 

Krijo objekte duke u bazuar në një objekt ekzistues duke përdorur klonimin.


Wikipedia thotë:

Modeli prototype është një model krijues në zhvillimin e softuerëve. Përdoret kur lloji i objekteve të cilat duhen të krijohen jane të determinuara nga një instance prototipe, e cila klonohet për të krijuar objekte të reja.


Thëne shkurt, ju mundëson të krijoni një kopje të një objekti ekzistues dhe të modifikoni atë në bazë të nevojave tuaja, në vend se të ballafaqoheni me krijimin e një objekt nga fillimi.


Shembull programatik:

Ne C# mund te bëhet thjesht duke përdorur MemberwiseClone()
class Sheep
{
  public string Name { get; set; }

  public string Category { get; set; }

  public Sheep(string name, string category)
  {
    Name = name;
    Category = category;
  }

  public Sheep Clone()
  {
    return MemberwiseClone() as Sheep;
  }
}


Kur të përdoret?

Kur kemi nevoje për një objekt që është i ngjashëm me një objekt ekzistues apo kur krijimi i një objekti është më i kushtueshëm sesa klonimi i tij.


Singleton


Shembull nga jeta e përditshme:

Mund të ekzistojë betëm një president i një vendi në të njëjtën kohë. Presidenti i njejtë duhet të marrë vendime, sa herë që ka nevojë. Presidenti në këtë rast është një singleton.


Me fjalë të thjeshta:

Sigurohet që është krijuar vetëm një klasë e vetme e një klase të caktuar.


Wikipedia thotë:

Në inxhinerinë softuerike, modeli singleton është një model i projektimit i cili kufizon inicializimin e një klase vetëm me një objekt. Kjo është e dobishme kur duhet vetëm nje objekt i një klase të caktuar për të kordinuar veprimet brenda një sistemi.


Singleton në fakt konsiderohet edhe si një anti-model, dhe përdorimi i tij i tepërt duhet të parandalohet. Nuk është domosdoshmërisht i keq dhe ka disa përdorime të dobishme, por duhet të përdoret me kujdes sepse sjell një gjendje globale në aplikacionin tuaj, dhe ndryshimi i saj në një vend mund të ndikojë në hapësirat tjera dhe është mjaft e vështië për debug. 


Shembull programatik:

Për të krijuar një singleton, duhet ta bëni konstruktorin privat, të ndaloni klonimin, të ndaloni metodat shtesë(extensions) dhe të krijoni një variabël statike për të mbajtur instancën.

public class President
{
  static President instance;
  // Private constructor
  private President()
  {
    //Hiding the Constructor
  }

  // Public constructor
  public static President get_instance()
  {
    if (instance == null) {
      instance = new President();
    }
    return instance;
  }
}

Dhe për të përdorur

President a = President.get_instance();
President b = President.get_instance();

Console.WriteLine((a==b).ToString()); //Output : true


Kjo është e tëra rreth modeleve krijuese të projektimit, Së shpejti do të vazhdojmë edhe me dy llojet tjera të modeleve të projektimit.



Granit Rexha
Software engineer. Loves to write.

Gjithashtu lexoni


0 komente