Obyekt-yönümlü Dizayn Şablonları

Obyekt-yönümlü Dizayn Şablonları

Dizayn şablonları proqram təminatı mühəndisliyində təkrar-təkrar qarşıya çıxan arxitektur problemlərin sistemli həllini təmin edən strukturlaşdırılmış yanaşmalardır.

Onlar obyekt-yönümlü proqramlaşdırmada “design patterns” və ya “dizayn nümünaləri” olaraq tanınır və proqramın çevikliyini, saxlanılmasını və genişlənməsini asanlaşdırır

Hazır funksiyalar və kitabxanalar konkret kod təmin etdiyi halda, dizayn şablonları müəyyən bir problemin ümumi həll konsepsiyasını təqdim edir və onu müxtəlif kontekstlərə uyğunlaşdırmaq mümkündür.

Bu şablonlar adətən üç əsas kateqoriyaya bölünür:

  1. Yaradıcı (Creational)
  2. Struktural (Structural)
  3. Davranışsal (Behavioural)

Dizayn Şablonlarının Növləri

Gəlin hər birini daha ətraflı şəkildə nəzərdən keçirək.

1. Yaradıcı Şablonlar

Yaradıcı dizayn şablonları obyektlərin yaradılması prosesini abstraktlaşdırır. Onlar sistemin obyektlərin necə yaradılması, birləşdirilməsi və təmsil olunmasından asılılığını azaldır. Sinif əsaslı yaradıcı şablon mirasdan istifadə edərək hansı sinifin yaradılacağını dəyişir, obyekt əsaslı yaradıcı şablon isə yaradılma işini başqa bir obyektə həvalə edir.

Bu şablonlarda iki təkrarlanan mövzu var. Birincisi, hamısı sistemin hansı konkret siniflərdən istifadə etdiyini gizləyir. İkincisi, həmin siniflərin obyektlərinin necə yaradıldığını və birləşdirildiyini gizləyir. Sistem isə obyektlər haqqında yalnız abstrakt siniflərin müəyyənləşdirdiyi interfeysləri bilir.

Əsas yaradıcı şablonlar:

  • Factory Method
  • Abstract Factory
  • Singleton
  • Builder

”Factory Method” Şablonu

Factory Method - obyektlərin yaradılması üçün interfeys müəyyən edir və instansiyalaşdırma məntiqini alt siniflərə həvalə edir. Müştəri kodu konkret siniflərə birbaşa istinad etmək əvəzinə factory interfeysi vasitəsilə obyektlər yaradır.

'Factory Method' Şablonu

class ComputerFactory {
  public Computer createComputer()  { 
    return new OfficeComputer(); 
  }
}

/* İstifadə nümunəsi */
ComputerFactory factory = new ComputerFactory();
Computer computer = factory.createComputer();

“Abstract Factory” Şablonu

Abstract Factory - əlaqəli obyekt ailələrinin yaradılması üçün interfeys təqdim edir. Konkret siniflər göstərmədən bir-biri ilə uyğun gələn obyektlərin yaradılmasını təmin edir; öz tərkibində Factory Method şablonunu istifadə edir.

'Abstract Factory' Şablonu

abstract class HardwareFactory {
  Computer createComputer();
}

class LenovoFactory extends HardwareFactory {
  @Override
  public Computer createComputer() { 
    return new ThinkPadX1Carbon(); 
  }
}

class AppleFactory extends HardwareFactory {
  @Override
  public Computer createComputer() { 
    return new MacBookAir(); 
  }
}

/* İstifadə nümunəsi */
HardwareFactory lenovoFactory = new LenovoFactory();
Computer lenovoComputer = lenovoFactory.createComputer();
HardwareFactory appleFactory = new AppleFactory();
Computer appleComputer = appleFactory.createComputer();

“Singleton” Şablonu

Singleton - sinifdən yalnız bir nümunənin yaradılmasını təmin edir və ona qlobal giriş nöqtəsi təqdim edir. Paylaşılan resursların idarə edilməsi üçün istifadə olunur.

'Singleton' Şablonu

class Config {
  private static final Config instance = new Config();

  public static Config getInstance() {
    return instance;
  }

  private Config() {}
}

/* İstifadə nümunəsi */
Config ref1 = Config.getInstance();
Config ref2 = Config.getInstance();

“Builder” Şablonu

Builder - mürəkkəb obyektlərin addım-addım qurulmasını təmin edir. Qurulma prosesini nəticə obyektindən ayırır və eyni proses ilə müxtəlif təsvirlər yarada bilir.

'Builder' Şablonu

class Car {
  private String engine;
  private String wheels;

  public static class Builder {
    private final Car car = new Car();

    public Builder engine(String engine) {
      car.engine = engine;
      return this;
    }

    public Builder wheels(String wheels) {
      car.wheels = wheels;
      return this;
    }

    public Car build() {
      return car;
    }
  }
}

/* İstifadə nümunəsi */
Car car = new Car.Builder()
  .engine("V8")
  .wheels("Sport")
  .build();

2. Struktural Şablonlar

Struktural şablonlar siniflərin və obyektlərin daha böyük quruluşlar yaratmaq üçün necə birləşdirilməsinə diqqət yetirir. İnterfeysləri və ya implementasiyaları kompozisiya etmək əvəzinə, struktural obyekt şablonları yeni funksionallıq əldə etmək üçün obyektlərin necə kompozisiya olunduğunu təsvir edir. Bu əlavə çeviklik onların tərkibini icra zamanı dəyişdirmək imkanından irəli gəlir, halbuki statik sinif birləşməsində bu mümkün deyil.

Ən çox istifadə edilən struktural şablonlar:

  • Decorator
  • Adapter
  • Facade
  • Proxy

”Decorator” Şablonu

Decorator - mövcud obyektlərə dinamik olaraq yeni funksionallıq əlavə etməyə imkan verir. Obyekti wrapper siniflərə bükərək onun davranışını genişləndirir.

'Decorator' Şablonu

interface Coffee {
  double cost();
}

class SimpleCoffee implements Coffee {
  public double cost() { return 2; }
}

abstract class CoffeeDecorator implements Coffee {
  protected Coffee coffee;
  CoffeeDecorator(Coffee coffee) { this.coffee = coffee; }
}

class Milk extends CoffeeDecorator {
  Milk(Coffee coffee) { super(coffee); }
  public double cost() { return coffee.cost() + 0.5; }
}

class Sugar extends CoffeeDecorator {
  Sugar(Coffee coffee) { super(coffee); }
  public double cost() { return coffee.cost() + 0.2; }
}

/* İstifadə nümunəsi */
Coffee coffee = new Sugar(new Milk(new SimpleCoffee()));
System.out.println(coffee.cost());

“Adapter” Şablonu

Adapter - uyğunsuz interfeyslərə malik siniflər arasında əməkdaşlıq təmin edir. Bir sinfin interfeysi digər sinfin gözlədiyi interfeysa çevirir.

'Adapter' Şablonu

interface ModernPrinter {
  void print(String text);
}

class OldPrinter {
  public void printOldFormat(String text) {
    System.out.println("OLD: " + text.toUpperCase());
  }
}

class PrinterAdapter implements ModernPrinter {
  private OldPrinter oldPrinter;
  
  public PrinterAdapter(OldPrinter oldPrinter) {
    this.oldPrinter = oldPrinter;
  }
  
  public void print(String text) {
    oldPrinter.printOldFormat(text);
  }
}

/* İstifadə nümunəsi */
ModernPrinter printer = new PrinterAdapter(new OldPrinter());
printer.print("Salam, dünya!");

“Facade” Şablonu

Facade - mürəkkəb alt sistemə sadə interfeys təqdim edir. Müştəri kodu üçün alt sistemin mürəkkəbliyini gizlədir və istifadəni asanlaşdırır.

'Facade' Şablonu

class TV {
  void on() { System.out.println("TV on"); }
}

class SoundSystem {
  void on() { System.out.println("Sound on"); }
}

class HomeTheater {
  private TV tv = new TV();
  private SoundSystem sound = new SoundSystem();
  
  public void watchMovie() {
    tv.on();
    sound.on();
  }
}

/* İstifadə nümunəsi */
new HomeTheater().watchMovie();

“Proxy” Şablonu

Proxy - digər obyektə giriş üçün nəzarət təmin edir. Əsl obyektin əvəzinə çıxış edir və ona müraciəti idarə edir, məhdudlaşdırır və ya optimallaşdırır.

'Proxy' Şablonu

interface HTTPClient {
  void request(String url);
}

class RealHTTPClient implements HTTPClient {
  public void request(String url) {
    System.out.println("Fetching: " + url);
  }
}

class CountingProxy implements HTTPClient {
  private RealHTTPClient client = new RealHTTPClient();
  private int requestCount = 0;

  public void request(String url) {
    requestCount++;
    System.out.println("Request #" + requestCount);
    client.request(url);
  }
}

/* İstifadə nümunəsi */
HTTPClient proxy = new CountingProxy();
proxy.request("https://example.com");
proxy.request("https://openai.com");
proxy.request("https://github.com");

3. Davranışsal Şablonlar

Davranışsal şablonlar alqoritm və obyektlər arasında məsuliyyətlərin paylanmasına diqqət yetirir. Onlar yalnız obyektlərin və ya siniflərin quruluşunu deyil, həm də onların bir-biri ilə ünsiyyət üsullarını təsvir edir. Bu şablonlar icraetmə zamanı izlənilməsi çətin olan mürəkkəb idarəetmə axınını xarakterizə edir. Nəzarət axınından diqqəti yayındıraraq, obyektlərin bir-biri ilə necə əlaqələndiyini ön plana çıxarmağa imkan verir.

Tanınmış davranışsal şablonlar:

  • Observer
  • Iterator
  • Visitor
  • Strategy

”Observer” Şablonu

Observer - bir obyekt (subject) dəyişdikdə, ona abunə olmuş bütün obyektlər (observers) avtomatik olaraq xəbərdar edilir və lazımi reaksiya göstərir.

'Observer' Şablonu

interface Investor { 
  void update(double price); 
}

class StockMarket {
  private List<Investor> investors = new ArrayList<>();
  void subscribe(Investor i) { investors.add(i); }
  void setPrice(double price) { investors.forEach(i -> i.update(price)); }
}

/* İstifadə nümunəsi */
StockMarket market = new StockMarket();
market.subscribe(p -> System.out.println("Nuran notified: ₼" + p));
market.subscribe(p -> System.out.println("Ofeliya notified: ₼" + p));
market.setPrice(100.5);
market.setPrice(102.75);

“Iterator” Şablonu

Iterator - kolleksiyanın daxili strukturunu açmadan onun elementlərinə ardıcıl giriş təmin edir. Müxtəlif növ kolleksiyalar üçün vahid dolaşma interfeysi yaradır.

'Iterator' Şablonu

class ContactList {
  private final String[] contacts = {"Nuran", "Əziz", "Murad"};

  public Iterator<String> iterator() {
    return new Iterator<String>() {
        private int index = 0;
        public boolean hasNext() { return index < contacts.length; }
        public String next() { return contacts[index++]; }
    };
  }
}

/* İstifadə nümunəsi */
ContactList contacts = new ContactList();
contacts.iterator().forEachRemaining(System.out::println);

“Visitor” Şablonu

Visitor - sinfin strukturunu dəyişmədən yeni əməliyyatların əlavə edilməsinə imkan verir. Əməliyyatları ayrı visitor siniflərində təşkil edir.

'Visitor' Şablonu

interface Entity { void accept(Inspector v); }

class Shop implements Entity {
  int revenue = 1000;
  public void accept(Inspector v) { v.visit(this); }
}

class Restaurant implements Entity {
  int customers = 50;
  int avgBill = 20;
  public void accept(Inspector v) { v.visit(this); }
}

class Home implements Entity {
  int income = 200;
  boolean hasPets = true;
  public void accept(Inspector v) { v.visit(this); }
}

interface Inspector {
  void visit(Shop s);
  void visit(Restaurant r);
  void visit(Home h);
}

class TaxCollector implements Inspector {
  public void visit(Shop s) { 
    System.out.println("Collected ₼" + (s.revenue * 0.1) + " from Shop"); 
  }
  public void visit(Restaurant r) { 
    System.out.println("Collected ₼" + (r.customers * r.avgBill * 0.05) + " from Restaurant"); 
  }
  public void visit(Home h) { 
    System.out.println("Collected ₼" + (h.income * (h.hasPets ? 0.07 : 0.05)) + " from Home"); 
  }
}

/* İstifadə nümunəsi */
Entity[] entities = { new Shop(), new Restaurant(), new Home() };
Inspector inspector = new TaxCollector();
for (Entity entity : entities) entity.accept(inspector);

“Strategy” Şablonu

Strategy - alqoritm ailəsini enkapsullaşdırır və onları bir-biri ilə əvəzlənə bilən edir. Bu pattern müştəri koduna runtime zamanında müxtəlif alqoritmləri seçmək və dəyişmək imkanı verir, alqoritmin implementasiyasını müştəri kodundan ayıraraq.

'Strategy' Şablonu

interface PaymentMethod {
  void pay(int amount);
}

class AbbCard implements PaymentMethod {
  public void pay(int amount) { 
      System.out.println("Paid ₼" + amount + " by ABB card"); 
  }
}

class PashaBankCard implements PaymentMethod {
  public void pay(int amount) { 
      System.out.println("Paid ₼" + amount + " by PashaBank card"); 
  }
}

class BankRespublikaCard implements PaymentMethod {
  public void pay(int amount) { 
      System.out.println("Paid ₼" + amount + " by BankRespublika card"); 
  }
}

class Checkout {
  public void pay(PaymentMethod method, int amount) {
      method.pay(amount); 
  }
}

/* İstifadə nümunəsi */
new Checkout().pay(new AbbCard(), 100);
new Checkout().pay(new PashaBankCard(), 100);
new Checkout().pay(new BankRespublikaCard(), 100);

Təbii ki, burada təqdim olunan dizayn şablonları mövcud bütün nümunələri əhatə etmir. Proqram təminatı mühəndisliyində çox sayda digər şablon mövcuddur, onları digər internet resursları və kitablardan öyrənə bilərsiniz.

Ümid edirəm ki, bu məqalə dizayn şablonları haqqında biliklərinizi genişləndirməyə və onları praktikada tətbiq etmək üçün faydalı oldu.

Diqqətə görə çox sağ olun.