ОНОЛ 02

Дизайн Паттернууд

ЛЕКЦ 02: ДИЗАЙН ПАТТЕРНУУД (Design Patterns)

Хичээлийн зорилго: Програм хангамжийн бүтээлтэд байнга давтагддаг асуудлуудыг шийдвэрлэх батлагдсан загваруудыг (design patterns) ойлгож, Java хэл дээр хэрэгжүүлэх чадвар эзэмших.



ХЭСЭГ 1: ҮНДСЭН ОЙЛГОЛТ БА ОНОЛ (Theory & Foundations)

1.1 Дизайн паттерн гэж юу вэ? (What is a Design Pattern?)

Тодорхойлолт

Дизайн паттерн (Design Pattern) гэдэг нь програм хангамжийн дизайнд байнга давтагддаг асуудлыг шийдвэрлэх батлагдсан загвар юм.

Gang of Four (GoF) номноос: "Дизайн паттерн гэдэг нь тодорхой контекст дэх ерөнхий дизайны асуудлыг шийдвэрлэхэд зориулсан, хоорондоо харилцах объект, классуудын тодорхойлолт юм."

Түүхэн мэдээлэл

Дизайн паттерн гэдэг ойлголт нь анх Кристофер Александер (Christopher Alexander) гэдэг архитекторын 1977 оны "A Pattern Language: Towns, Buildings, Construction" номноос үүдэлтэй. Тэрээр барилга, хот байгуулалтад байнга давтагддаг асуудлуудыг шийдвэрлэх загваруудыг баримтжуулсан.

1995 онд Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides нар Александерийн санааг програм хангамжийн ертөнцөд авчирч "Design Patterns: Elements of Reusable Object-Oriented Software" номыг хэвлэсэн. Энэ 4 зохиогчийг "Gang of Four" (GoF) буюу "Дөрвөн хүний бүлэг" гэж нэрлэдэг.

Амьдрал дээрх зүйрлэл

Зүйрлэл 1 — Хоолны жор: Тогооч хоол бүрийг эхнээс нь зохион бодохгүй. Үүний оронд батлагдсан жор ашигладаг. Жор нь "ямар асуудлыг (юу хоол хийх), ямар орцоор, ямар дарааллаар шийдвэрлэх" гэдгийг тодорхойлдог. Дизайн паттерн ч яг ийм — програмчлалын "жор".

Зүйрлэл 2 — Барилгын зураг төсөл: Архитектор байшин бүрийг тэг-ээс зохиохгүй. "3 өрөө байр", "гал тогооны стандарт зохион байгуулалт" гэх мэт батлагдсан загварууд байдаг. Дизайн паттерн нь програмын "архитектурын загвар" юм.

Паттерн яагаад чухал вэ?

  1. Батлагдсан шийдэл — Олон жилийн туршлагаар шалгагдсан, алдаа бага
  2. Нийтлэг хэл — Хөгжүүлэгчид хоорондоо "Энд Singleton хэрэглэ" гэхэд бүгд ойлгоно
  3. Дахин ашиглалт — Нэг удаа сурч, олон удаа ашиглана
  4. Код уншигдахуйц — Паттерн мэддэг хүн кодыг амархан ойлгоно
  5. Уян хатан дизайн — Өөрчлөлтөд нээлттэй, засвар хялбар

Паттерны 3 бүрэлдэхүүн хэсэг

Паттерн бүр гурван зүйлийг тодорхойлдог:

БүрэлдэхүүнТайлбарЗүйрлэл
Асуудал (Problem)Ямар нөхцөлд хэрэглэх вэ?"Хоол амтгүй байна, юу хийх вэ?"
Контекст (Context)Ямар нөхцөл байдалд хэрэглэх вэ?"Монгол зочин байна, Монгол хоол хийх хэрэгтэй"
Шийдэл (Solution)Хэрхэн шийдвэрлэх вэ?"Бууз хийх жор: гурил, мах, сонгино..."

1.2 Паттерны 3 том ангилал (Three Categories of Patterns)

GoF 23 паттерныг 3 том бүлэгт хуваадаг:

А) Бүтээх паттернууд (Creational Patterns) — 5 ш

Объект ЯАЖЕ ҮҮСГЭХ-тэй холбоотой. Объект үүсгэх процессыг хийсвэрлэж, системийг объект яаж үүссэнээс хамааралгүй болгодог.

Зүйрлэл: Автомашины үйлдвэр — захиалагч "Би седан авах" гэнэ. Үйлдвэр доторх нарийн үйл явцыг мэдэх шаардлагагүй — зүгээр л машин гарч ирнэ.

#ПаттернТовч тайлбар
1SingletonЗөвхөн НЭГ объект үүсгэж, бүх газраас хандах
2Factory MethodОбъект үүсгэхийг дэд класст шилжүүлэх
3Abstract FactoryХамааралтай объектуудын гэр бүлийг нэг дор үүсгэх
4BuilderНарийн төвөгтэй объектыг алхам алхмаар бүтээх
5PrototypeОдоо байгаа объектыг хуулбарлаж шинэ объект үүсгэх

Б) Бүтцийн паттернууд (Structural Patterns) — 7 ш

Класс, объектуудыг ЯАЖЕ НЭГТГЭХ-тэй холбоотой. Объектуудыг том бүтцэд хэрхэн зохион байгуулахыг тодорхойлдог.

Зүйрлэл: LEGO — жижиг хэсгүүдийг хоорондоо холбож том бүтэц бүтээх. Хэсэг бүр өөрөө ч ажилладаг, бусадтай холбогдсон ч ажилладаг.

#ПаттернТовч тайлбар
1AdapterХоёр нийцдэггүй интерфейсийг холбох
2BridgeХийсвэрлэлийг хэрэгжүүлэлтээс салгах
3CompositeОбъектуудыг модлог (tree) бүтцэд зохион байгуулах
4DecoratorОбъектод шинэ функц динамикаар нэмэх
5FacadeНарийн системд хялбар интерфейс хангах
6FlyweightОлон тооны ижил объектын санах ойг хэмнэх
7ProxyӨөр объектыг орлох, хандалтыг хянах

В) Зан төлөвийн паттернууд (Behavioral Patterns) — 11 ш

Объектууд ЯАЖЕ ХАРИЛЦАХ-тай холбоотой. Алгоритм, хариуцлагыг хуваарилах аргуудыг тодорхойлдог.

Зүйрлэл: Хөл бөмбөгийн баг — тоглогч бүр өөрийн үүрэгтэй (хамгаалагч, дунд, довтлогч) бөгөөд тэд хоорондоо дохио, дамжуулалтаар харилцдаг. Паттерн нь энэ "харилцааны дүрмийг" тодорхойлдог.

#ПаттернТовч тайлбар
1ObserverОбъектын төлөв өөрчлөгдөхөд бусдад мэдэгдэх
2StrategyАлгоритмыг сольж болдог болгох
3CommandХүсэлтийг объект болгож капсулжуулах
4StateОбъект төлөвөөс хамааран зан төлөвөө өөрчлөх
5Template MethodАлгоритмын араг ясыг тодорхойлж, дэд класст нарийн хэсгийг шилжүүлэх
6IteratorЦуглуулгын элементүүдийг дараалуулан хандах
7MediatorОбъектуудын харилцааг нэг цэгт төвлөрүүлэх
8MementoОбъектын өмнөх төлөвийг хадгалж, сэргээх
9Chain of ResponsibilityХүсэлтийг гинжин хэлхээгээр дамжуулах
10VisitorБүтцээ өөрчлөхгүйгээр шинэ үйлдэл нэмэх
11InterpreterХэлний дүрэм тодорхойлж, тайлбарлах

1.3 Бүтээх паттернууд дэлгэрэнгүй (Creational Patterns in Detail)

1.3.1 Singleton — Ганцхан объект

Асуудал: Зарим тохиолдолд класснаас зөвхөн нэг объект үүсэх ёстой. Жишээ нь: мэдээллийн сангийн холболт, тохиргооны менежер, лог бичигч.

Зүйрлэл: Монгол улсад Ерөнхийлөгч ганцхан байдаг. Хэн ч шинээр Ерөнхийлөгч "үүсгэж" чадахгүй — одоо байгаа Ерөнхийлөгчийг л авч ашиглана.

Шийдэл:

  1. Constructor-ийг private болгох → гаднаас new хийж чадахгүй
  2. Статик getInstance() метод хангах → Нэг л объект буцаана
public class DatabaseConnection {
    // 1. Ганцхан instance-ийг static талбарт хадгалах
    private static DatabaseConnection instance;

    // 2. Constructor-ийг private болгох — гаднаас үүсгэж чадахгүй
    private DatabaseConnection() {
        System.out.println("Мэдээллийн сантай холбогдлоо!");
    }

    // 3. Ганцхан instance-д хандах цорын ганц арга
    public static DatabaseConnection getInstance() {
        if (instance == null) {              // Хэрэв instance үүсээгүй бол
            instance = new DatabaseConnection();  // Үүсгэнэ
        }
        return instance;                     // Байгаа instance-ийг буцаана
    }

    public void query(String sql) {
        System.out.println("SQL ажиллууллаа: " + sql);
    }
}

// Хэрэглээ:
// DatabaseConnection db1 = DatabaseConnection.getInstance();
// DatabaseConnection db2 = DatabaseConnection.getInstance();
// db1 == db2 → true (яг адилхан объект!)

Хэзээ ашиглах: Мэдээллийн сангийн холболт, Logger, Configuration, Thread pool

1.3.2 Factory Method — Үйлдвэрийн арга

Асуудал: Ямар класснаас объект үүсгэхийг код ажиллаж байх үед шийдэх шаардлагатай. Шинэ төрөл нэмэхэд одоо байгаа кодыг өөрчлөхгүй байх.

Зүйрлэл: Пиццаны дэлгүүр — Захиалагч "Пепперони пицца" гэнэ. Дэлгүүр дотор ЯАЖЕ бэлтгэхийг (овен, температур, хугацаа) мэдэх шаардлагагүй. Дэлгүүр (Factory) бэлэн пицца (Object) гаргаж өгнө.

// Бүтээгдэхүүний интерфейс
interface Notification {
    void send(String message);
}

// Бодит бүтээгдэхүүнүүд
class EmailNotification implements Notification {
    @Override
    public void send(String message) {
        System.out.println("📧 Email илгээлээ: " + message);
    }
}

class SMSNotification implements Notification {
    @Override
    public void send(String message) {
        System.out.println("📱 SMS илгээлээ: " + message);
    }
}

class PushNotification implements Notification {
    @Override
    public void send(String message) {
        System.out.println("🔔 Push мэдэгдэл: " + message);
    }
}

// Factory — Объект үүсгэх үйлдвэр
class NotificationFactory {
    public static Notification create(String type) {
        switch (type.toLowerCase()) {
            case "email": return new EmailNotification();
            case "sms":   return new SMSNotification();
            case "push":  return new PushNotification();
            default: throw new IllegalArgumentException("Тодорхойгүй төрөл: " + type);
        }
    }
}

// Хэрэглээ:
// Notification notif = NotificationFactory.create("email");
// notif.send("Сайн байна уу!");
// → 📧 Email илгээлээ: Сайн байна уу!

Давуу тал: Шинэ төрөл нэмэхэд зөвхөн Factory-д нэг case нэмнэ → Бусад код өөрчлөгдөхгүй

1.3.3 Builder — Алхам алхмаар бүтээгч

Асуудал: Олон параметртэй нарийн төвөгтэй объект үүсгэх. Constructor-т 10+ параметр дамжуулах нь ойлгомжгүй.

Зүйрлэл: Бургер захиалах — "Том талх, давхар мах, бяслаг тийм, лоолийн соус, сонгиногүй" гэж алхам алхмаар хэлдэг. Бүгдийг нэг дор хэлэх шаардлагагүй.

public class Student {
    private String name;       // Заавал
    private int age;           // Заавал
    private String email;      // Нэмэлт
    private String phone;      // Нэмэлт
    private String address;    // Нэмэлт

    // Private constructor — зөвхөн Builder-ээр үүсгэнэ
    private Student(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.email = builder.email;
        this.phone = builder.phone;
        this.address = builder.address;
    }

    // Дотоод Builder класс
    public static class Builder {
        private String name;       // Заавал
        private int age;           // Заавал
        private String email;      // Нэмэлт
        private String phone;      // Нэмэлт
        private String address;    // Нэмэлт

        public Builder(String name, int age) {   // Заавал талбарууд
            this.name = name;
            this.age = age;
        }

        public Builder email(String email) {     // Нэмэлт талбарууд
            this.email = email;
            return this;                         // this буцааж chain хийх
        }

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

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

        public Student build() {                 // Эцсийн объект үүсгэх
            return new Student(this);
        }
    }

    @Override
    public String toString() {
        return "Оюутан: " + name + ", " + age + " нас"
            + (email != null ? ", " + email : "")
            + (phone != null ? ", " + phone : "");
    }
}

// Хэрэглээ — уншихад маш ойлгомжтой:
// Student student = new Student.Builder("Бат", 20)
//     .email("bat@email.com")
//     .phone("99112233")
//     .build();

1.3.4 Prototype — Хуулбарлагч

Асуудал: Объект үүсгэх нь нөөц их шаарддаг (мэдээллийн сангаас уншдаг, тооцоолол хийдэг). Одоо байгаа объектыг хуулбарлах нь хурдан.

Зүйрлэл: Ажлын байрны хүсэлтийн маягт — Эхний хүсэлтийг анхнаас бөглөнө. Дараагийнхийг ХУУЛБАРЛАЖ, өөрчлөх зүйлээ л засна.

public class Document implements Cloneable {
    private String title;
    private String content;

    public Document(String title, String content) {
        this.title = title;
        this.content = content;
    }

    // Prototype — clone() метод
    @Override
    public Document clone() {
        try {
            return (Document) super.clone();   // Хуулбар үүсгэх
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

    public void setTitle(String title) { this.title = title; }
    public String toString() { return title + ": " + content; }
}

// Хэрэглээ:
// Document original = new Document("Гэрээ", "Энэ бол гэрээний агуулга...");
// Document copy = original.clone();         // Хуулбарлах
// copy.setTitle("Гэрээ - Хувилбар 2");     // Зөвхөн нэрийг өөрчлөх

1.4 Бүтцийн паттернууд дэлгэрэнгүй (Structural Patterns in Detail)

1.4.1 Adapter — Тохируулагч

Асуудал: Хоёр класс хоорондоо нийцдэггүй интерфейстэй ч хамт ажиллах шаардлагатай.

Зүйрлэл: Гадаадад аялахад залгуурын хэлбэр өөр байдаг. Adapter (залгуурын хувиргагч) ашиглаж Монгол залгуурыг Европын розеткад тохируулдаг шиг.

// Хуучин систем — зөвхөн XML мэддэг
class OldAnalytics {
    public void analyzeXML(String xmlData) {
        System.out.println("XML шинжилгээ: " + xmlData);
    }
}

// Шинэ систем — JSON ашигладаг
interface ModernAnalytics {
    void analyzeJSON(String jsonData);
}

// Adapter — Хуучин системийг шинэ интерфейсээр ашиглуулна
class AnalyticsAdapter implements ModernAnalytics {
    private OldAnalytics oldAnalytics;

    public AnalyticsAdapter(OldAnalytics oldAnalytics) {
        this.oldAnalytics = oldAnalytics;
    }

    @Override
    public void analyzeJSON(String jsonData) {
        // JSON-ийг XML руу хувиргаж, хуучин системд дамжуулна
        String xmlData = convertJsonToXml(jsonData);
        oldAnalytics.analyzeXML(xmlData);
    }

    private String convertJsonToXml(String json) {
        return "<data>" + json + "</data>";   // Хялбаршуулсан хувиргалт
    }
}

1.4.2 Facade — Нүүр хаалга

Асуудал: Нарийн төвөгтэй системтэй харилцахад олон класс, метод дуудах шаардлагатай.

Зүйрлэл: Зочид буудлын ресепшн — Та ресепшнд л хэлнэ, тэд цэвэрлэгээ, хоол, такси бүгдийг зохион байгуулна. Та хоол хийгчтэй, жолоочтой шууд ярилцах шаардлагагүй.

// Нарийн төвөгтэй дэд системүүд
class VideoFile { /* видео файл уншигч */ }
class AudioExtractor { public void extract() { System.out.println("Аудио задлав"); } }
class VideoCompressor { public void compress() { System.out.println("Видео шахав"); } }
class CodecFactory { public void getCodec() { System.out.println("Кодек сонгов"); } }

// Facade — Нэг энгийн интерфейс
class VideoConverter {
    public void convert(String filename, String format) {
        System.out.println("=== " + filename + " → " + format + " руу хөрвүүлж байна ===");
        new CodecFactory().getCodec();
        new AudioExtractor().extract();
        new VideoCompressor().compress();
        System.out.println("=== Хөрвүүлэлт амжилттай! ===");
    }
}

// Хэрэглээ — маш энгийн:
// VideoConverter converter = new VideoConverter();
// converter.convert("movie.avi", "mp4");

1.4.3 Decorator — Чимэглэгч

Асуудал: Объектод ажиллах үед шинэ функц динамикаар нэмэх. Удамшилаар шийдвэл класс тэсрэлт (class explosion) үүснэ.

Зүйрлэл: Кофе — Энгийн кофе + сүү = сүүтэй кофе. Сүүтэй кофе + чихэр = чихэртэй сүүтэй кофе. Хэрэглэгч хүссэн нэмэлтүүдээ давхарлаж "чимэглэнэ".

// Суурь интерфейс
interface Coffee {
    double getCost();
    String getDescription();
}

// Суурь бүтээгдэхүүн
class SimpleCoffee implements Coffee {
    @Override
    public double getCost() { return 2000; }
    @Override
    public String getDescription() { return "Энгийн кофе"; }
}

// Decorator суурь класс
abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    public CoffeeDecorator(Coffee coffee) { this.coffee = coffee; }
}

// Бодит decorator-ууд
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) { super(coffee); }
    @Override
    public double getCost() { return coffee.getCost() + 500; }
    @Override
    public String getDescription() { return coffee.getDescription() + " + Сүү"; }
}

class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) { super(coffee); }
    @Override
    public double getCost() { return coffee.getCost() + 200; }
    @Override
    public String getDescription() { return coffee.getDescription() + " + Чихэр"; }
}

// Хэрэглээ:
// Coffee coffee = new SimpleCoffee();                    // Энгийн кофе: 2000₮
// coffee = new MilkDecorator(coffee);                    // + Сүү: 2500₮
// coffee = new SugarDecorator(coffee);                   // + Чихэр: 2700₮
// System.out.println(coffee.getDescription() + " = " + coffee.getCost() + "₮");
// → "Энгийн кофе + Сүү + Чихэр = 2700₮"

1.4.4 Proxy — Орлогч

Асуудал: Объектод хандахыг хянах, хойшлуулах, эсвэл нэмэлт логик нэмэх шаардлагатай.

Зүйрлэл: Нарийн бичгийн дарга — Та захиралтай уулзахын тулд нарийн бичгийн даргаар дамжина. Тэр таны цагийг товлох, хандалтыг шалгах, захиралд мэдэгдэх зэргийг хийнэ.

interface Image {
    void display();
}

// Бодит объект — Их нөөц шаарддаг
class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();                    // Их цаг зарцуулдаг
    }

    private void loadFromDisk() {
        System.out.println("Дискнээс ачааллаж байна: " + filename);
    }

    @Override
    public void display() {
        System.out.println("Зураг харуулж байна: " + filename);
    }
}

// Proxy — Бодит объектын орлогч
class ProxyImage implements Image {
    private String filename;
    private RealImage realImage;           // Lazy loading

    public ProxyImage(String filename) {
        this.filename = filename;          // Зүгээр нэрийг хадгална
    }

    @Override
    public void display() {
        if (realImage == null) {            // Анх удаа дуудахад л ачаална
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

1.5 Зан төлөвийн паттернууд дэлгэрэнгүй (Behavioral Patterns in Detail)

1.5.1 Observer — Ажиглагч

Асуудал: Нэг объектын төлөв өөрчлөгдөхөд олон объектод автоматаар мэдэгдэх шаардлагатай.

Зүйрлэл: YouTube суваг дагах (subscribe) — Шинэ видео нийтлэгдэхэд бүх дагагчдад мэдэгдэл очдог. Дагагч нэмэх, хасах нь сувагт нөлөөлөхгүй.

import java.util.ArrayList;
import java.util.List;

// Observer интерфейс — Мэдэгдэл хүлээн авагч
interface Subscriber {
    void update(String channelName, String videoTitle);
}

// Subject — Мэдэгдэл илгээгч (YouTube суваг)
class YouTubeChannel {
    private String name;
    private List<Subscriber> subscribers = new ArrayList<>();

    public YouTubeChannel(String name) { this.name = name; }

    public void subscribe(Subscriber sub) {
        subscribers.add(sub);
        System.out.println("✅ Шинэ дагагч нэмэгдлээ!");
    }

    public void unsubscribe(Subscriber sub) {
        subscribers.remove(sub);
    }

    // Шинэ видео нийтлэхэд БҮХ дагагчдад мэдэгдэнэ
    public void publishVideo(String title) {
        System.out.println("🎬 Шинэ видео: " + title);
        for (Subscriber sub : subscribers) {
            sub.update(name, title);          // Бүх дагагчид мэдэгдэх
        }
    }
}

// Бодит Observer
class User implements Subscriber {
    private String name;

    public User(String name) { this.name = name; }

    @Override
    public void update(String channelName, String videoTitle) {
        System.out.println("🔔 " + name + " → " + channelName + ": \"" + videoTitle + "\"");
    }
}

// Хэрэглээ:
// YouTubeChannel channel = new YouTubeChannel("TechMN");
// channel.subscribe(new User("Бат"));
// channel.subscribe(new User("Болд"));
// channel.publishVideo("Java Design Patterns");
// → 🔔 Бат → TechMN: "Java Design Patterns"
// → 🔔 Болд → TechMN: "Java Design Patterns"

1.5.2 Strategy — Стратеги

Асуудал: Нэг ажлыг олон өөр аргаар хийж болох бөгөөд ажиллах үед аргаа сольж болох ёстой.

Зүйрлэл: Ажил руугаа явах — Автобусаар, таксиар, алхаж, дугуйгаар... Зорилго нэг (ажил руу хүрэх), арга олон. Цаг агаар, мөнгөнөөсөө хамааран аргаа сонгоно.

// Strategy интерфейс
interface PaymentStrategy {
    void pay(int amount);
}

// Бодит стратегиуд
class CreditCardPayment implements PaymentStrategy {
    private String cardNumber;
    public CreditCardPayment(String cardNumber) { this.cardNumber = cardNumber; }
    @Override
    public void pay(int amount) {
        System.out.println("💳 Картаар төлөв: " + amount + "₮ (Карт: " + cardNumber + ")");
    }
}

class QPayPayment implements PaymentStrategy {
    private String phoneNumber;
    public QPayPayment(String phoneNumber) { this.phoneNumber = phoneNumber; }
    @Override
    public void pay(int amount) {
        System.out.println("📱 QPay-ээр төлөв: " + amount + "₮ (Утас: " + phoneNumber + ")");
    }
}

class CashPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println("💵 Бэлнээр төлөв: " + amount + "₮");
    }
}

// Context — Стратегийг ашиглагч
class ShoppingCart {
    private PaymentStrategy paymentStrategy;

    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;     // Стратегийг солих
    }

    public void checkout(int amount) {
        paymentStrategy.pay(amount);         // Сонгосон стратегиар төлөх
    }
}

// Хэрэглээ:
// ShoppingCart cart = new ShoppingCart();
// cart.setPaymentStrategy(new QPayPayment("99112233"));
// cart.checkout(50000);
// → 📱 QPay-ээр төлөв: 50000₮ (Утас: 99112233)

1.5.3 Template Method — Загвар арга

Асуудал: Алгоритмын ерөнхий бүтэц ижил, гэхдээ зарим алхмууд өөр өөр.

Зүйрлэл: Хоол хийх ерөнхий дараалал — (1) орцыг бэлтгэ, (2) хоолоо хий, (3) таваглаж өг. Бууз ч, хуушуур ч, банш ч энэ дарааллаар хийгдэнэ — зөвхөн нарийн алхмууд нь өөр.

// Template Method — Ерөнхий араг яс
abstract class MealPreparation {
    // Template method — дарааллыг тодорхойлно (final = дэд класс өөрчилж чадахгүй)
    public final void prepareMeal() {
        prepareIngredients();
        cook();
        serve();
    }

    abstract void prepareIngredients();  // Дэд класс тодорхойлно
    abstract void cook();                // Дэд класс тодорхойлно

    void serve() {                       // Ерөнхий хэрэгжүүлэлт
        System.out.println("🍽️ Таваглаж өгөв!");
    }
}

class BuuzPreparation extends MealPreparation {
    @Override
    void prepareIngredients() {
        System.out.println("🥟 Гурил зуурч, мах бэлтгэв");
    }
    @Override
    void cook() {
        System.out.println("♨️ Жигнэж байна... 20 минут");
    }
}

class PizzaPreparation extends MealPreparation {
    @Override
    void prepareIngredients() {
        System.out.println("🍕 Гурил дэлгэж, соус, бяслаг тавив");
    }
    @Override
    void cook() {
        System.out.println("🔥 Зууханд шаржигнуулж байна... 15 минут");
    }
}

1.5.4 Command — Команд

Асуудал: Хүсэлтийг объект болгож хадгалах, дараалалд оруулах, буцаах (undo) шаардлагатай.

Зүйрлэл: Ресторанд захиалга өгөх — Зөөгч таны захиалгыг цаасан дээр бичиж (Command объект), гал тогоонд дамжуулна. Захиалгыг цуцлах (undo), дараалалд оруулах боломжтой.

// Command интерфейс
interface Command {
    void execute();
    void undo();
}

// Receiver — Бодит ажлыг гүйцэтгэгч
class Light {
    public void turnOn()  { System.out.println("💡 Гэрэл асав!"); }
    public void turnOff() { System.out.println("🌑 Гэрэл унтрав!"); }
}

// Бодит Command-ууд
class LightOnCommand implements Command {
    private Light light;
    public LightOnCommand(Light light) { this.light = light; }
    @Override
    public void execute() { light.turnOn(); }
    @Override
    public void undo() { light.turnOff(); }
}

// Invoker — Command-ыг ажиллуулагч
class RemoteControl {
    private Command lastCommand;

    public void pressButton(Command command) {
        command.execute();
        lastCommand = command;
    }

    public void pressUndo() {
        if (lastCommand != null) {
            lastCommand.undo();
        }
    }
}

1.6 Паттерн хэрэглэх зарчмууд (When and How to Use Patterns)

Хэрэглэх ёстой үед:

  1. Давтагддаг асуудал илэрсэн үед
  2. Уян хатан дизайн шаардлагатай үед
  3. Багийн харилцааг сайжруулах үед

Хэрэглэх ёсгүй үед:

  1. Хэт энгийн асуудалд паттерн хэрэглэх нь over-engineering
  2. Паттерн нь кодын нарийн төвөгтэй байдлыг нэмдэг — зөвхөн шаардлагатай үед ашиглах
  3. Паттерн хэрэглэх гэж хэрэглэхгүй — Асуудлаа тодорхой ойлгоод, паттерн тохирох эсэхийг шалгах

"When Not to Use Design Patterns" — GoF номноос: "Хамгийн энгийн шийдэл нь хамгийн сайн шийдэл. Паттерн нь зөвхөн нарийн төвөгтэй байдал зөвтгөгдөх үед ашиглагдах ёстой."

SOLID зарчмууд ба Design Patterns

Дизайн паттернууд нь SOLID зарчмуудыг хэрэгжүүлэхэд тусалдаг:

SOLID зарчимТайлбарХолбоотой паттерн
S — Single ResponsibilityНэг класс нэг л үүрэгтэйCommand, Strategy
O — Open/ClosedӨргөтгөхөд нээлттэй, өөрчлөхөд хаалттайDecorator, Observer
L — Liskov SubstitutionДэд класс эцэг классыг орлож чадахFactory, Template Method
I — Interface SegregationИнтерфейсийг жижиглэхAdapter, Facade
D — Dependency InversionХийсвэрлэлээс хамаарах, бодит хэрэгжүүлэлтээс бишFactory, Strategy


ХЭСЭГ 2: ТҮЛХҮҮР ҮГ БА МЭРГЭЖЛИЙН НЭР ТОМЬЁО (Keywords & Glossary)

#Англи нэр томьёоМонгол утгаДэлгэрэнгүй тайлбар
1Design PatternДизайн паттерн / Загвар хэвПрограм хангамжийн дизайнд байнга давтагддаг асуудлыг шийдвэрлэх батлагдсан загвар. Хоолны жортой адил — нэг удаа сурч, олон удаа ашиглана.
2Gang of Four (GoF)Дөрвөн хүний бүлэг1995 онд "Design Patterns" номыг бичсэн 4 зохиогч: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides.
3Creational PatternБүтээх паттернОбъект ЯАЖЕ үүсгэхтэй холбоотой паттерн. Объект үүсгэх процессыг хийсвэрлэж, системийг уян хатан болгодог.
4Structural PatternБүтцийн паттернКласс, объектуудыг ЯАЖЕ нэгтгэхтэй холбоотой. Том бүтэц зохион байгуулах арга замыг тодорхойлдог.
5Behavioral PatternЗан төлөвийн паттернОбъектууд ЯАЖЕ харилцахтай холбоотой. Алгоритм, хариуцлагыг хуваарилах аргуудыг тодорхойлдог.
6SingletonГанцаардмалЗөвхөн НЭГ объект үүсгэж, глобал хандалт хангах паттерн. Ерөнхийлөгч ганцхан байдаг шиг.
7Factory MethodҮйлдвэрийн аргаОбъект үүсгэх үүргийг дэд класст шилжүүлдэг. Пиццаны дэлгүүр шиг — захиалга өгөхөд бэлэн бүтээгдэхүүн гарна.
8Abstract FactoryХийсвэр үйлдвэрХамааралтай объектуудын ГЭР БҮЛИЙГ нэг дор үүсгэдэг. Тавилга дэлгүүрийн каталог шиг — "Модерн" сонговол бүх тавилга модерн.
9BuilderБүтээгчНарийн төвөгтэй объектыг алхам алхмаар бүтээх. Бургер захиалах шиг — орц бүрийг тусдаа сонгоно.
10PrototypeЭх загвар / ХуулбарлагчОдоо байгаа объектыг хуулбарлаж шинэ объект үүсгэх. Маягтыг хуулбарлаад зөвхөн өөрчлөх зүйлээ засах шиг.
11AdapterТохируулагч / Залгуур хувиргагчНийцдэггүй хоёр интерфейсийг холбодог. Гадаадын залгуурын хувиргагч шиг.
12FacadeНүүр хаалгаНарийн системд хялбар, ганцхан интерфейс хангадаг. Зочид буудлын ресепшн шиг — бүх зүйлийг нэг цэгээс шийднэ.
13DecoratorЧимэглэгчОбъектод шинэ функц динамикаар давхарлаж нэмдэг. Кофенд сүү, чихэр нэмдэг шиг.
14ProxyОрлогч / ТөлөөлөгчӨөр объектын орлуулагч бөгөөд хандалтыг хянаж, нэмэлт логик нэмдэг. Нарийн бичгийн дарга шиг.
15ObserverАжиглагчОбъектын төлөв өөрчлөгдөхөд бүх дагагчдад мэдэгдэдэг. YouTube subscribe шиг.
16StrategyСтратегиОлон алгоритмаас ажиллах үед сонгож болдог. Ажил руугаа явах олон арга шиг — автобус, такси, алхах.
17Template MethodЗагвар аргаАлгоритмын бүтцийг тогтоож, нарийн алхмуудыг дэд класст шилжүүлдэг. Бууз, хуушууры ерөнхий "хоол хийх" дараалал ижил, нарийн нь өөр.
18CommandКомандХүсэлтийг объект болгож хадгалах, дараалалд оруулах, буцаах (undo). Ресторанд захиалгын цаас шиг.
19StateТөлөвОбъект дотоод төлөвөөс хамаарч зан төлөвөө өөрчилдөг. Гар утас: дуугүй горимд дуугардаггүй, чимээтэй горимд дуугардаг.
20IteratorДавталтчинЦуглуулгын элементүүдийг дотоод бүтцийг далдалж дараалуулан хандах. TV-ийн суваг солигч шиг — дарах бүрт дараагийн суваг.
21MediatorЗуучлагчОбъектуудын шууд харилцааг зогсоож, бүхнийг нэг зуучлагчаар дамжуулдаг. Нисэх буудлын удирдах цамхаг шиг.
22MementoДурсгал / ХадгалагчОбъектын өмнөх төлөвийг хадгалж, хэрэгтэй үед сэргээдэг. Тоглоомын "save point" шиг.
23Chain of ResponsibilityХариуцлагын гинжХүсэлтийг гинжин хэлхээгээр дамжуулж, тохирох зохицуулагч олтол дамжуулдаг. Байгууллагад өргөдөл дамжуулах шиг.
24VisitorЗочинОбъектын бүтцийг өөрчлөхгүйгээр шинэ үйлдэл нэмэх. Гэрийн эзэн зочинд гэрээ нээж өгдөг шиг — зочин шинэ үйлдэл хийнэ.
25BridgeГүүрХийсвэрлэлийг хэрэгжүүлэлтээс салгаж, тус тусдаа хөгжүүлэх. Удирдлагын пульт (хийсвэрлэл) ба ТВ (хэрэгжүүлэлт) тусдаа.
26CompositeНийлмэлОбъектуудыг мод (tree) бүтцэд зохион байгуулж, нэг объект шиг хандах. Файлын систем: фолдер дотор файл ба фолдер байна.
27FlyweightХөнгөн жинОлон ижил объектын нийтлэг өгөгдлийг хуваалцуулж санах ойг хэмнэдэг. Тоглоомд олон мод ижил бүтэцтэй — зүгээр байрлал нь өөр.
28InterpreterТайлбарлагчХэлний дүрэм тодорхойлж, өгүүлбэрийг тайлбарлах. SQL query-г задлан шинжлэх шиг.
29SOLIDSOLID зарчмуудОбъект хандлагат дизайны 5 суурь зарчим: Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, Dependency Inversion.
30Open/Closed PrincipleНээлттэй/Хаалттай зарчимКласс ӨРГӨТГӨХӨД нээлттэй, ӨӨРЧЛӨХӨД хаалттай байх ёстой. Decorator, Strategy паттернууд үүнийг хэрэгжүүлдэг.
31Dependency InversionХамааралын урвууДээд түвшний модуль доод түвшний модулиас хамаарах ёсгүй — хоёулаа хийсвэрлэлээс хамаарах ёстой.
32Loose CouplingСул холбоосМодулиуд хоорондоо аль болох бага хамааралтай байх. Паттернуудын ихэнх нь үүнийг зорьдог.
33InterfaceИнтерфейсКласс ямар үйлдлүүд хийж чадахыг тодорхойлсон гэрээ. Хэрэгжүүлэлтийг заадаггүй, зөвхөн "юу хийх"-ийг заадаг.
34Abstract ClassХийсвэр классДутуу хэрэгжүүлэлттэй (abstract method-тэй) класс. Шууд объект үүсгэж болохгүй, зөвхөн удамшуулна.
35InheritanceУдамшилНэг классаас шинж чанар, үйлдлүүдийг өвлөн авах. Хүүхэд эцэг эхийнхээ зарим шинж чанарыг өвлөдөг шиг.
36CompositionБүтэц / НийлбэрОбъектыг бусад объектуудаас бүрдүүлэх. "HAS-A" харилцаа. Машин = мотор + дугуй + бие.
37EncapsulationКапсулжуулалтӨгөгдөл ба методыг нэгтгэж, гаднаас шууд хандахыг хязгаарлах.
38PolymorphismОлон хэлбэрт байдалНэг интерфейсээр өөр өөр хэрэгжүүлэлтийг дуудах чадвар. Strategy, Observer паттернуудын суурь.
39Over-engineeringХэт инженерчлэлШаардлагагүй нарийн төвөгтэй шийдэл хэрэглэх. Паттерн хэрэггүй газар паттерн хэрэглэх жишээ.
40Design for ChangeӨөрчлөлтөд зориулсан дизайнGoF-ийн гол зарчим — систем дизайнлахдаа зайлшгүй ирэх өөрчлөлтийг урьдчилан тооцох.