Назад к вопросам
Middle
70
questionbank

Какие паттерны проектирования, кроме Singleton, вы использовали в своих проектах?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

  • Factory Method: Использовался для создания объектов различных типов внутри родительского класса, делегируя создание подклассам. Это позволяло сделать код более гибким при добавлении новых подтипов.

    // Пример Factory Method
    interface Product {
        void doSomething();
    }
    
    class ConcreteProductA implements Product {
        @Override
        public void doSomething() {
            System.out.println("Product A");
        }
    }
    
    class ConcreteProductB implements Product {
        @Override
        public void doSomething() {
            System.out.println("Product B");
        }
    }
    
    abstract class Creator {
        public abstract Product factoryMethod();
    
        public void operate() {
            Product product = factoryMethod();
            product.doSomething();
        }
    }
    
    class ConcreteCreatorA extends Creator {
        @Override
        public Product factoryMethod() {
            return new ConcreteProductA();
        }
    }
    
    class ConcreteCreatorB extends Creator {
        @Override
        public Product factoryMethod() {
            return new ConcreteProductB();
        }
    }
    
  • Observer: Применялся для реализации системы подписки/уведомления, где один объект (издатель) уведомляет множество зависимых объектов (подписчиков) об изменении своего состояния.

    // Пример Observer
    import java.util.ArrayList;
    import java.util.List;
    
    interface Observer {
        void update(String message);
    }
    
    class ConcreteObserverA implements Observer {
        @Override
        public void update(String message) {
            System.out.println("Observer A received: " + message);
        }
    }
    
    class ConcreteObserverB implements Observer {
        @Override
        public void update(String message) {
            System.out.println("Observer B received: " + message);
        }
    }
    
    class Subject {
        private List<Observer> observers = new ArrayList<>();
        private String state;
    
        public void attach(Observer observer) {
            observers.add(observer);
        }
    
        public void detach(Observer observer) {
            observers.remove(observer);
        }
    
        public void setState(String state) {
            this.state = state;
            notifyObservers();
        }
    
        private void notifyObservers() {
            for (Observer observer : observers) {
                observer.update(state);
            }
        }
    }
    
  • Strategy: Использовался для определения семейства алгоритмов, инкапсуляции каждого из них и возможности их взаимозаменяемости. Это позволяет клиенту выбирать алгоритм на лету.

    // Пример Strategy
    interface Strategy {
        double execute(double a, double b);
    }
    
    class AddStrategy implements Strategy {
        @Override
        public double execute(double a, double b) {
            return a + b;
        }
    }
    
    class SubtractStrategy implements Strategy {
        @Override
        public double execute(double a, double b) {
            return a - b;
        }
    }
    
    class MultiplyStrategy implements Strategy {
        @Override
        public double execute(double a, double b) {
            return a * b;
        }
    }
    
    class Context {
        private Strategy strategy;
    
        public void setStrategy(Strategy strategy) {
            this.strategy = strategy;
        }
    
        public double executeStrategy(double a, double b) {
            return strategy.execute(a, b);
        }
    }
    
  • Decorator: Применялся для динамического добавления обязанностей к объектам, сохраняя ту же сигнатуру. Это гибкая альтернатива наследованию для расширения функциональности.

    // Пример Decorator
    interface Coffee {
        String getDescription();
        double getCost();
    }
    
    class SimpleCoffee implements Coffee {
        @Override
        public String getDescription() {
            return "Simple coffee";
        }
    
        @Override
        public double getCost() {
            return 1.0;
        }
    }
    
    abstract class CoffeeDecorator implements Coffee {
        protected Coffee decoratedCoffee;
    
        public CoffeeDecorator(Coffee decoratedCoffee) {
            this.decoratedCoffee = decoratedCoffee;
        }
    
        @Override
        public String getDescription() {
            return decoratedCoffee.getDescription();
        }
    
        @Override
        public double getCost() {
            return decoratedCoffee.getCost();
        }
    }
    
    class MilkDecorator extends CoffeeDecorator {
        public MilkDecorator(Coffee decoratedCoffee) {
            super(decoratedCoffee);
        }
    
        @Override
        public String getDescription() {
            return decoratedCoffee.getDescription() + ", Milk";
        }
    
        @Override
        public double getCost() {
            return decoratedCoffee.getCost() + 0.5;
        }
    }
    
    class SugarDecorator extends CoffeeDecorator {
        public SugarDecorator(Coffee decoratedCoffee) {
            super(decoratedCoffee);
        }
    
        @Override
        public String getDescription() {
            return decoratedCoffee.getDescription() + ", Sugar";
        }
    
        @Override
        public double getCost() {
            return decoratedCoffee.getCost() + 0.2;
        }
    }
    
  • Template Method: Использовался для определения скелета алгоритма в суперклассе, позволяя подклассам переопределять конкретные шаги без изменения общей структуры алгоритма.

    // Пример Template Method
    abstract class Game {
        abstract void initialize();
        abstract void startPlay();
        abstract void endPlay();
    
        // template method
        public final void playGame() {
            initialize();
            startPlay();
            endPlay();
        }
    }
    
    class Chess extends Game {
        @Override
        void initialize() {
            System.out.println("Initializing Chess Game...");
        }
    
        @Override
        void startPlay() {
            System.out.println("Starting Chess Game...");
        }
    
        @Override
        void endPlay() {
            System.out.println("Ending Chess Game...");
        }
    }
    
    class Monopoly extends Game {
        @Override
        void initialize() {
            System.out.println("Initializing Monopoly Game...");
        }
    
        @Override
        void startPlay() {
            System.out.println("Starting Monopoly Game...");
        }
    
        @Override
        void endPlay() {
            System.out.println("Ending Monopoly Game...");
        }
    }
    

Также сталкивался с применением Dependency Injection (часто реализуется фреймворками, но понимание принципов важно).