Skip to content
IRC-CodingIRC-Coding
Design PatternsSingletonObserverFactoryAdapterIteratorStrategyDecoratorАлгоритмыОсновы

Каталог Design Patterns: Singleton, Observer, Factory

Важные Design Patterns с реализациями. Singleton, Observer, Factory, Adapter, Iterator, Strategy, Decorator, Template Method с примерами.

S

schutzgeist

12 min read
Каталог Design Patterns: Singleton, Observer, Factory

Каталог Design Patterns: Singleton, Observer, Factory, Adapter и другие

Другие статьи про Design Patterns:

Статья представляет полный каталог ключевых Design Patterns с примерами Singleton, Observer, Factory, Adapter, Iterator, Strategy, Decorator и Template Method с практическими реализациями.

Суть вопроса

Design Patterns — это проверенные шаблоны решений для типичных проблем в разработке ПО. Они позволяют создавать переиспользуемые, легко поддерживаемые и расширяемые архитектуры.

Краткое описание

Design Patterns (проектные паттерны) — это описанные решения типичных задач в объектно-ориентированной разработке. Их систематизировала «Gang of Four» (GoF), документируя практики, проверенные временем.

Категории паттернов GoF:

Creational Patterns (Порождающие паттерны)

  • Singleton: гарантирует существование только одного экземпляра
  • Factory: создание объектов без прямого использования конструктора
  • Abstract Factory: создание семейств связанных объектов
  • Builder: пошаговое создание сложных объектов

Structural Patterns (Структурные паттерны)

  • Adapter: приведение несовместимых интерфейсов в соответствие
  • Decorator: динамическое добавление функциональности
  • Facade: упрощённый интерфейс для подсистем
  • Proxy: представитель для объекта

Behavioral Patterns (Поведенческие паттерны)

  • Observer: уведомления об изменении состояния
  • Strategy: взаимозаменяемые алгоритмы
  • Iterator: последовательный доступ к элементам коллекции
  • Template Method: скелет алгоритма, переопределяемые шаги

Ключевые пункты для подготовки

  • Singleton: глобальный экземпляр, потокобезопасная реализация
  • Observer: отношение Subject-Observer, слабая связанность
  • Factory: централизация создания объектов, полиморфизм
  • Adapter: приведение интерфейсов, композиция или наследование
  • Iterator: унифицированный доступ к контейнерам, hasNext/next
  • Strategy: взаимозаменяемые алгоритмы, принцип Open-Closed
  • Decorator: расширение функциональности, динамическое применение
  • Template Method: скелет алгоритма, hook-методы
  • Для сертификаций: важны для архитектуры и проектирования ПО

Основные компоненты

  1. Singleton: один экземпляр на класс
  2. Observer: связь 1:n для уведомлений
  3. Factory: создание объектов без оператора new
  4. Adapter: приведение интерфейсов
  5. Iterator: последовательный доступ к коллекциям
  6. Strategy: взаимозаменяемые алгоритмы
  7. Decorator: динамическое расширение функциональности
  8. Template Method: скелет алгоритма с изменяемыми шагами

Практические примеры

1. Паттерн Singleton

// Потокобезопасный Singleton с ленивой инициализацией
public class DatabaseConnection {
    private static volatile DatabaseConnection instance;
    private final String connectionUrl;
    
    // Приватный конструктор предотвращает создание извне
    private DatabaseConnection() {
        this.connectionUrl = "jdbc:mysql://localhost:3306/mydb";
        // Имитация установления соединения
        System.out.println("Datenbankverbindung hergestellt");
    }
    
    // Double-Checked Locking для потокобезопасности
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            synchronized (DatabaseConnection.class) {
                if (instance == null) {
                    instance = new DatabaseConnection();
                }
            }
        }
        return instance;
    }
    
    public void executeQuery(String sql) {
        System.out.println("Führe aus: " + sql);
    }
    
    public String getConnectionUrl() {
        return connectionUrl;
    }
}

// Использование
public class SingletonDemo {
    public static void main(String[] args) {
        DatabaseConnection conn1 = DatabaseConnection.getInstance();
        DatabaseConnection conn2 = DatabaseConnection.getInstance();
        
        System.out.println("Gleiches Objekt: " + (conn1 == conn2)); // true
        System.out.println("Connection URL: " + conn1.getConnectionUrl());
        
        conn1.executeQuery("SELECT * FROM users");
    }
}

2. Паттерн Observer

import java.util.*;

// Subject (Observable)
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// Concrete Subject
class WeatherStation implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private float temperature;
    private float humidity;
    
    public void setMeasurements(float temperature, float humidity) {
        this.temperature = temperature;
        this.humidity = humidity;
        measurementsChanged();
    }
    
    public void measurementsChanged() {
        notifyObservers();
    }
    
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }
    
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    
    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity);
        }
    }
}

// Observer
interface Observer {
    void update(float temperature, float humidity);
}

// Concrete Observer
class TemperatureDisplay implements Observer {
    private float temperature;
    
    @Override
    public void update(float temperature, float humidity) {
        this.temperature = temperature;
        display();
    }
    
    public void display() {
        System.out.println("Temperaturanzeige: " + temperature + "°C");
    }
}

class HumidityDisplay implements Observer {
    private float humidity;
    
    @Override
    public void update(float temperature, float humidity) {
        this.humidity = humidity;
        display();
    }
    
    public void display() {
        System.out.println("Feuchtigkeitsanzeige: " + humidity + "%");
    }
}

// Использование
public class ObserverDemo {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();
        
        TemperatureDisplay tempDisplay = new TemperatureDisplay();
        HumidityDisplay humidityDisplay = new HumidityDisplay();
        
        // Регистрируем наблюдателей
        weatherStation.registerObserver(tempDisplay);
        weatherStation.registerObserver(humidityDisplay);
        
        // Изменяем измерения
        weatherStation.setMeasurements(25.5f, 65.0f);
        weatherStation.setMeasurements(26.0f, 63.5f);
        
        // Удаляем наблюдателя
        weatherStation.removeObserver(humidityDisplay);
        weatherStation.setMeasurements(24.8f, 67.2f);
    }
}

3. Паттерн Factory

// Интерфейс Product
interface Shape {
    void draw();
}

// Конкретные Products
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Zeichne Kreis");
    }
}

class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Zeichne Rechteck");
    }
}

class Triangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Zeichne Dreieck");
    }
}

// Factory
class ShapeFactory {
    public Shape createShape(String shapeType) {
        if (shapeType == null || shapeType.isEmpty()) {
            return null;
        }
        
        switch (shapeType.toUpperCase()) {
            case "CIRCLE":
                return new Circle();
            case "RECTANGLE":
                return new Rectangle();
            case "TRIANGLE":
                return new Triangle();
            default:
                throw new IllegalArgumentException("Unbekannter Shape-Typ: " + shapeType);
        }
    }
}

// Использование
public class FactoryDemo {
    public static void main(String[] args) {
        ShapeFactory factory = new ShapeFactory();
        
        // Создаём фигуры без оператора new
        Shape circle = factory.createShape("CIRCLE");
        Shape rectangle = factory.createShape("RECTANGLE");
        Shape triangle = factory.createShape("TRIANGLE");
        
        // Используем фигуры
        circle.draw();
        rectangle.draw();
        triangle.draw();
        
        // Factory с конфигурацией
        createShapesFromConfig(factory);
    }
    
    private static void createShapesFromConfig(ShapeFactory factory) {
        String[] shapes = {"CIRCLE", "RECTANGLE", "CIRCLE", "TRIANGLE"};
        
        for (String shapeType : shapes) {
            try {
                Shape shape = factory.createShape(shapeType);
                shape.draw();
            } catch (IllegalArgumentException e) {
                System.err.println("Fehler: " + e.getMessage());
            }
        }
    }
}

4. Adapter Pattern

// Target Interface
interface MediaPlayer {
    void play(String audioType, String fileName);
}

// Adaptee (inkompatible Schnittstelle)
interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

// Concrete Adaptee
class VlcPlayer implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Spielt VLC-Datei: " + fileName);
    }
    
    @Override
    public void playMp4(String fileName) {
        // Nicht unterstützt
    }
}

class Mp4Player implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        // Nicht unterstützt
    }
    
    @Override
    public void playMp4(String fileName) {
        System.out.println("Spielt MP4-Datei: " + fileName);
    }
}

// Adapter
class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer advancedMusicPlayer;
    
    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer = new Mp4Player();
        }
    }
    
    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMusicPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMusicPlayer.playMp4(fileName);
        }
    }
}

// Client
class AudioPlayer implements MediaPlayer {
    private MediaAdapter mediaAdapter;
    
    @Override
    public void play(String audioType, String fileName) {
        // Eigene Formate unterstützen
        if (audioType.equalsIgnoreCase("mp3")) {
            System.out.println("Spielt MP3-Datei: " + fileName);
        }
        // Andere Formate über Adapter
        else if (audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")) {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("Ungültiges Medienformat: " + audioType);
        }
    }
}

// Verwendung
public class AdapterDemo {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();
        
        audioPlayer.play("mp3", "song.mp3");
        audioPlayer.play("mp4", "video.mp4");
        audioPlayer.play("vlc", "movie.vlc");
        audioPlayer.play("avi", "video.avi");
    }
}

Паттерн Adapter используется, когда нужно интегрировать несовместимые интерфейсы. Давайте рассмотрим пример медиаплеера, который поддерживает MP3, но требует воспроизведения VLC и MP4 файлов с помощью специализированных player’ов.

AudioPlayer поддерживает только MP3. Для других форматов мы создаём MediaAdapter, который преобразует вызовы общего интерфейса в вызовы специальных методов. Адаптер скрывает сложность работы с несовместимыми интерфейсами.

Когда вызывается play("vlc", "movie.vlc"), адаптер создаёт VlcPlayer и вызывает его метод playVlc(). То же происходит с MP4 файлами.

5. Iterator Pattern

import java.util.*;

// Aggregate Interface
interface Container {
    Iterator getIterator();
}

// Iterator Interface
interface Iterator {
    boolean hasNext();
    Object next();
}

// Concrete Aggregate
class NameRepository implements Container {
    private String[] names = {"Alice", "Bob", "Charlie", "Diana"};
    
    @Override
    public Iterator getIterator() {
        return new NameIterator();
    }
    
    private class NameIterator implements Iterator {
        private int index;
        
        @Override
        public boolean hasNext() {
            return index < names.length;
        }
        
        @Override
        public Object next() {
            if (this.hasNext()) {
                return names[index++];
            }
            return null;
        }
    }
}

// Verwendung
public class IteratorDemo {
    public static void main(String[] args) {
        NameRepository namesRepository = new NameRepository();
        
        for (Iterator iterator = namesRepository.getIterator(); iterator.hasNext();) {
            String name = (String) iterator.next();
            System.out.println("Name: " + name);
        }
        
        // Vergleich mit Java Standard Iterator
        List<String> nameList = Arrays.asList("Alice", "Bob", "Charlie", "Diana");
        System.out.println("\nMit Java Iterator:");
        for (Iterator<String> it = nameList.iterator(); it.hasNext();) {
            String name = it.next();
            System.out.println("Name: " + name);
        }
        
        // Enhanced for loop (syntactic sugar)
        System.out.println("\nMit Enhanced for loop:");
        for (String name : nameList) {
            System.out.println("Name: " + name);
        }
    }
}

Паттерн Iterator позволяет последовательно перемещаться по элементам коллекции без раскрытия её внутренней структуры. Вместо прямого доступа к массиву или списку мы предоставляем объект, который управляет обходом.

NameRepository содержит приватное поле names с именами. Метод getIterator() возвращает внутренний класс NameIterator, который реализует интерфейс Iterator. Клиент работает только с методами hasNext() и next(), ничего не зная о деталях хранения данных.

Java имеет встроенный Iterator, который работает аналогично. Enhanced for loop - это синтаксический сахар над Iterator API, позволяющий писать более читаемый код.

6. Strategy Pattern

// Strategy Interface
interface PaymentStrategy {
    void pay(int amount);
}

// Concrete Strategies
class CreditCardPayment implements PaymentStrategy {
    private String name;
    private String cardNumber;
    private String cvv;
    private String date;
    
    public CreditCardPayment(String name, String cardNumber, String cvv, String date) {
        this.name = name;
        this.cardNumber = cardNumber;
        this.cvv = cvv;
        this.date = date;
    }
    
    @Override
    public void pay(int amount) {
        System.out.println(amount + " € mit Kreditkarte bezahlt.");
        System.out.println("Karteninhaber: " + name);
        System.out.println("Kartennummer: **** **** **** " + cardNumber.substring(cardNumber.length() - 4));
    }
}

class PayPalPayment implements PaymentStrategy {
    private String email;
    private String password;
    
    public PayPalPayment(String email, String password) {
        this.email = email;
        this.password = password;
    }
    
    @Override
    public void pay(int amount) {
        System.out.println(amount + " € mit PayPal bezahlt.");
        System.out.println("PayPal-Account: " + email);
    }
}

class BitcoinPayment implements PaymentStrategy {
    private String walletAddress;
    
    public BitcoinPayment(String walletAddress) {
        this.walletAddress = walletAddress;
    }
    
    @Override
    public void pay(int amount) {
        System.out.println(amount + " € mit Bitcoin bezahlt.");
        System.out.println("Wallet: " + walletAddress.substring(0, 8) + "...");
    }
}

// Context
class ShoppingCart {
    private PaymentStrategy paymentStrategy;
    
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }
    
    public void checkout(int amount) {
        if (paymentStrategy == null) {
            throw new IllegalStateException("Keine Zahlungsmethode ausgewählt");
        }
        paymentStrategy.pay(amount);
    }
}

// Verwendung
public class StrategyDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();
        
        // Verschiedene Zahlungsmethoden
        cart.setPaymentStrategy(new CreditCardPayment(
            "Max Mustermann", "1234567890123456", "123", "12/25"));
        cart.checkout(100);
        
        System.out.println("---");
        
        cart.setPaymentStrategy(new PayPalPayment("max@example.com", "password123"));
        cart.checkout(250);
        
        System.out.println("---");
        
        cart.setPaymentStrategy(new BitcoinPayment("1A2B3C4D5E6F7G8H9I0J"));
        cart.checkout(500);
        
        // Dynamische Strategieauswahl
        dynamicStrategySelection(cart);
    }
    
    private static void dynamicStrategySelection(ShoppingCart cart) {
        Scanner scanner = new Scanner(System.in);
        
        System.out.println("\nWählen Sie Zahlungsmethode:");
        System.out.println("1. Kreditkarte");
        System.out.println("2. PayPal");
        System.out.println("3. Bitcoin");
        
        int choice = scanner.nextInt();
        int amount = 75;
        
        switch (choice) {
            case 1:
                cart.setPaymentStrategy(new CreditCardPayment(
                    "Test User", "1111222233334444", "999", "12/24"));
                break;
            case 2:
                cart.setPaymentStrategy(new PayPalPayment("test@example.com", "test123"));
                break;
            case 3:
                cart.setPaymentStrategy(new BitcoinPayment("ABCDEF123456789"));
                break;
            default:
                System.out.println("Ungültige Auswahl");
                return;
        }
        
        cart.checkout(amount);
        scanner.close();
    }
}

Паттерн Strategy инкапсулирует различные алгоритмы в отдельных классах, позволяя менять их во время выполнения. Вместо большого количества условных операторов в одном классе мы создаём семейство стратегий, реализующих общий интерфейс.

В нашем примере ShoppingCart не зависит от конкретного способа оплаты. Мы устанавливаем стратегию через setPaymentStrategy() и вызываем checkout(). Корзина делегирует работу текущей стратегии, независимо от её конкретной реализации.

Каждый способ оплаты имеет свою логику: кредитная карта требует данных карты, PayPal работает с электронной почтой, Bitcoin использует адрес кошелька. Благодаря Strategy клиент может добавлять новые методы оплаты без изменения ShoppingCart.

dynamicStrategySelection() демонстрирует выбор стратегии в runtime на основе пользовательского ввода. Это показывает гибкость паттерна при обработке динамических сценариев.

7. Паттерн Decorator

// Интерфейс компонента
interface Coffee {
    String getDescription();
    double getCost();
}

// Конкретный компонент
class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "Einfacher Kaffee";
    }
    
    @Override
    public double getCost() {
        return 2.0;
    }
}

// Абстрактный декоратор
abstract class CoffeeDecorator implements Coffee {
    protected Coffee decoratedCoffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.decoratedCoffee = coffee;
    }
    
    @Override
    public String getDescription() {
        return decoratedCoffee.getDescription();
    }
    
    @Override
    public double getCost() {
        return decoratedCoffee.getCost();
    }
}

// Конкретные декораторы
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return super.getDescription() + ", Milch";
    }
    
    @Override
    public double getCost() {
        return super.getCost() + 0.5;
    }
}

class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return super.getDescription() + ", Zucker";
    }
    
    @Override
    public double getCost() {
        return super.getCost() + 0.2;
    }
}

class WhippedCreamDecorator extends CoffeeDecorator {
    public WhippedCreamDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return super.getDescription() + ", Schlagobers";
    }
    
    @Override
    public double getCost() {
        return super.getCost() + 1.0;
    }
}

// Использование
public class DecoratorDemo {
    public static void main(String[] args) {
        // Простой кофе
        Coffee coffee = new SimpleCoffee();
        System.out.println(coffee.getDescription() + " kostet " + coffee.getCost() + "€");
        
        // С молоком
        coffee = new MilkDecorator(coffee);
        System.out.println(coffee.getDescription() + " kostet " + coffee.getCost() + "€");
        
        // С сахаром
        coffee = new SugarDecorator(coffee);
        System.out.println(coffee.getDescription() + " kostet " + coffee.getCost() + "€");
        
        // С взбитыми сливками
        coffee = new WhippedCreamDecorator(coffee);
        System.out.println(coffee.getDescription() + " kostet " + coffee.getCost() + "€");
        
        // Гибкая комбинация
        Coffee customCoffee = new SimpleCoffee();
        customCoffee = new MilkDecorator(customCoffee);
        customCoffee = new SugarDecorator(customCoffee);
        customCoffee = new SugarDecorator(customCoffee); // Doppelter Zucker
        
        System.out.println("\nCustom Kaffee:");
        System.out.println(customCoffee.getDescription() + " kostet " + customCoffee.getCost() + "€");
    }
}

8. Паттерн Template Method

// Абстрактный класс с Template Method
abstract class DataProcessor {
    
    // Template Method (final, чтобы подклассы не переопределяли)
    public final void processData() {
        loadData();
        if (validateData()) {
            transformData();
            saveData();
        } else {
            handleError();
        }
        cleanup();
    }
    
    // Абстрактные методы (должны быть реализованы в подклассах)
    protected abstract void loadData();
    protected abstract void transformData();
    protected abstract void saveData();
    
    // Hook Methods (могут быть переопределены)
    protected boolean validateData() {
        return true; // Стандартная реализация
    }
    
    protected void handleError() {
        System.out.println("Datenvalidierung fehlgeschlagen!");
    }
    
    protected void cleanup() {
        System.out.println("Aufräumen abgeschlossen");
    }
}

// Конкретная реализация
class CSVDataProcessor extends DataProcessor {
    private String data;
    
    @Override
    protected void loadData() {
        System.out.println("Lade CSV-Daten...");
        data = "name,age,city\nAlice,25,Berlin\nBob,30,Hamburg";
    }
    
    @Override
    protected void transformData() {
        System.out.println("Transformiere CSV-Daten...");
        // Конвертирование CSV в JSON
        data = data.replace("\n", ",").replace("name", "\"name\"")
                    .replace("age", "\"age\"").replace("city", "\"city\"");
    }
    
    @Override
    protected void saveData() {
        System.out.println("Speichere transformierte Daten...");
        System.out.println("Daten: " + data);
    }
    
    @Override
    protected boolean validateData() {
        // CSV-специфичная валидация
        return data != null && data.contains("name") && data.contains("age");
    }
}

class XMLDataProcessor extends DataProcessor {
    private String data;
    
    @Override
    protected void loadData() {
        System.out.println("Lade XML-Daten...");
        data = "<users><user name='Alice' age='25'/><user name='Bob' age='30'/></users>";
    }
    
    @Override
    protected void transformData() {
        System.out.println("Transformiere XML-Daten...");
        // Конвертирование XML в JSON
        data = "[{\"name\":\"Alice\",\"age\":25},{\"name\":\"Bob\",\"age\":30}]";
    }
    
    @Override
    protected void saveData() {
        System.out.println("Speichere transformierte Daten...");
        System.out.println("Daten: " + data);
    }
    
    @Override
    protected void handleError() {
        System.out.println("XML-Verarbeitungsfehler!");
        // Специальная обработка ошибок для XML
    }
}

// Использование
public class TemplateMethodDemo {
    public static void main(String[] args) {
        System.out.println("=== CSV Prozessor ===");
        DataProcessor csvProcessor = new CSVDataProcessor();
        csvProcessor.processData();
        
        System.out.println("\n=== XML Prozessor ===");
        DataProcessor xmlProcessor = new XMLDataProcessor();
        xmlProcessor.processData();
        
        // Демонстрация паттерна Template Method
        demonstrateTemplateMethod();
    }
    
    private static void demonstrateTemplateMethod() {
        System.out.println("\n=== Template Method Demonstration ===");
        
        // Последовательность алгоритма всегда одинакова, варьируется только реализация
        DataProcessor[] processors = {
            new CSVDataProcessor(),
            new XMLDataProcessor()
        };
        
        for (DataProcessor processor : processors) {
            System.out.println("\nVerarbeite mit " + processor.getClass().getSimpleName() + ":");
            processor.processData();
        }
    }
}

Обзор категорий паттернов

Creational Patterns (Порождающие паттерны)

ПаттернНазначениеПример
SingletonТолько один экземплярDatabase Connection
FactoryЦентрализация создания объектовShape Factory
Abstract FactoryСемейства объектовGUI Factory
BuilderПошаговое построение сложных объектовStringBuilder

Структурные паттерны

ПаттернНазначениеПример
AdapterАдаптация несовместимых интерфейсовMedia Adapter
DecoratorДинамическое расширение функциональностиCoffee Decorator
FacadeУпрощённый интерфейсHome Theater
ProxyЗаместитель объектаVirtual Proxy

Поведенческие паттерны

ПаттернНазначениеПример
ObserverУведомление об измененияхWeather Station
StrategyВзаимозаменяемые алгоритмыPayment Strategy
IteratorПоследовательный обходCollection Iterator
Template MethodШаблон алгоритмаData Processor

Преимущества Design Patterns

Переиспользуемость

  • Проверенные решения можно применять в разных проектах
  • Снижается трудозатраты на разработку
  • Обеспечивается единообразие архитектуры

Поддерживаемость

  • Чёткое распределение ответственности
  • Слабая связанность компонентов
  • Упрощенные модификация и расширение

Коммуникация

  • Единый язык общения между разработчиками
  • Задокументированные подходы к решениям
  • Быстрое понимание кода при работе в команде

Качество

  • Протестированные и надёжные решения
  • Меньше багов и проблем
  • Повышенное качество кода

Частые экзаменационные вопросы

  1. Когда применяется паттерн Singleton? Когда нужна единственная глобальная экземпляр класса (подключение к БД, логгер).

  2. В чём отличие между Adapter и Decorator? Adapter приводит несовместимые интерфейсы в соответствие, а Decorator добавляет новую функциональность.

  3. Объясните паттерн Observer! Subject уведомляет Observer об изменении состояния, обеспечивая слабую связанность компонентов.

  4. Почему Template Method полезен? Определяет основной скелет алгоритма, позволяя подклассам реализовывать отдельные шаги.

Основные источники

  1. https://refactoring.guru/design-patterns
  2. https://www.oreilly.com/library/view/head-first-design/0596007124
  3. https://en.wikipedia.org/wiki/Software_design_pattern

Рекомендуемая литература: Design Patterns

Keine Bücher für Kategorie "design-patterns" gefunden.

Назад к блогу
Share:

Nächster Artikel in Архитектура программного обеспечения

Weiterlesen
UML диаграммы: классы, последовательность, активность

Похожие статьи