Какие знаешь методы реализации шаблонного проектирования?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Паттерны проектирования (Design Patterns)
Паттерны проектирования — это переиспользуемые решения для типичных проблем в проектировании программного обеспечения. Они были классифицированы книгой «Gang of Four» на три основные категории.
1. Порождающие паттерны (Creational Patterns)
Эти паттерны управляют созданием объектов.
Singleton (Одиночка)
Гарантирует, что класс имеет только один экземпляр и предоставляет глобальный доступ.
// Ленивая инициализация (thread-safe)
public class DatabaseConnection {
private static DatabaseConnection instance;
private DatabaseConnection() {}
public static synchronized DatabaseConnection getInstance() {
if (instance == null) {
instance = new DatabaseConnection();
}
return instance;
}
}
// Double-checked locking (более эффективно)
public class Database {
private static volatile Database instance;
private Database() {}
public static Database getInstance() {
if (instance == null) {
synchronized (Database.class) {
if (instance == null) {
instance = new Database();
}
}
}
return instance;
}
}
// Статичный инициализатор (с Java 5)
public class Config {
public static final Config INSTANCE = new Config();
private Config() {}
}
Factory Method (Фабричный метод)
Создание объектов через методы вместо прямого использования new.
public interface DatabaseDriver {
void connect(String url);
}
public class PostgreSQLDriver implements DatabaseDriver {
@Override
public void connect(String url) {
System.out.println("Connecting to PostgreSQL: " + url);
}
}
public class MySQLDriver implements DatabaseDriver {
@Override
public void connect(String url) {
System.out.println("Connecting to MySQL: " + url);
}
}
// Фабрика
public class DatabaseDriverFactory {
public static DatabaseDriver createDriver(String driverType) {
return switch (driverType.toLowerCase()) {
case "postgresql" -> new PostgreSQLDriver();
case "mysql" -> new MySQLDriver();
default -> throw new IllegalArgumentException("Unknown driver: " + driverType);
};
}
}
// Использование
public class Application {
public static void main(String[] args) {
DatabaseDriver driver = DatabaseDriverFactory.createDriver("postgresql");
driver.connect("jdbc:postgresql://localhost/db");
}
}
Abstract Factory (Абстрактная фабрика)
Создание семейств связанных объектов.
// Семейство кроссбраузерных элементов
public interface Button {
void click();
}
public interface TextBox {
void setText(String text);
}
public class WindowsButton implements Button {
@Override
public void click() {
System.out.println("Windows button clicked");
}
}
public class MacButton implements Button {
@Override
public void click() {
System.out.println("Mac button clicked");
}
}
// Абстрактная фабрика
public interface UIFactory {
Button createButton();
TextBox createTextBox();
}
public class WindowsUIFactory implements UIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextBox createTextBox() {
return new WindowsTextBox();
}
}
public class MacUIFactory implements UIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextBox createTextBox() {
return new MacTextBox();
}
}
Builder (Строитель)
Построение сложных объектов пошагово.
public class User {
private final String name;
private final String email;
private final int age;
private final String phone;
private final String address;
private User(Builder builder) {
this.name = builder.name;
this.email = builder.email;
this.age = builder.age;
this.phone = builder.phone;
this.address = builder.address;
}
public static class Builder {
private String name;
private String email;
private int age;
private String phone;
private String address;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder email(String email) {
this.email = email;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder phone(String phone) {
this.phone = phone;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public User build() {
return new User(this);
}
}
}
// Использование
User user = new User.Builder()
.name("Alice")
.email("alice@test.com")
.age(30)
.phone("+1234567890")
.build();
Prototype (Прототип)
Создание новых объектов путём копирования существующего.
public class User implements Cloneable {
private String name;
private String email;
@Override
public User clone() {
try {
return (User) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
// Использование
User original = new User("Alice", "alice@test.com");
User copy = original.clone(); // Новый объект с теми же данными
2. Структурные паттерны (Structural Patterns)
Эти паттерны определяют связи между объектами.
Adapter (Адаптер)
Преобразование несовместимого интерфейса.
// Старый интерфейс
public interface OldPaymentService {
void pay(double amount);
}
// Новый интерфейс
public interface NewPaymentService {
void processPayment(PaymentRequest request);
}
public class PaymentAdapter implements NewPaymentService {
private OldPaymentService oldService;
public PaymentAdapter(OldPaymentService oldService) {
this.oldService = oldService;
}
@Override
public void processPayment(PaymentRequest request) {
// Адаптируем новый интерфейс к старому
oldService.pay(request.getAmount());
}
}
Decorator (Декоратор)
Динамическое добавление функциональности к объекту.
public interface Coffee {
double cost();
String describe();
}
public class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 2.0;
}
@Override
public String describe() {
return "Simple coffee";
}
}
public class MilkDecorator implements Coffee {
private Coffee coffee;
public MilkDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double cost() {
return coffee.cost() + 0.5;
}
@Override
public String describe() {
return coffee.describe() + ", with milk";
}
}
public class SugarDecorator implements Coffee {
private Coffee coffee;
public SugarDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double cost() {
return coffee.cost() + 0.25;
}
@Override
public String describe() {
return coffee.describe() + ", with sugar";
}
}
// Использование
Coffee coffee = new SimpleCoffee(); // $2.00
coffee = new MilkDecorator(coffee); // $2.50
coffee = new SugarDecorator(coffee); // $2.75
System.out.println(coffee.cost() + " - " + coffee.describe());
Facade (Фасад)
Упрощение сложного интерфейса.
public class HomeTheaterFacade {
private Projector projector;
private AudioSystem audioSystem;
private Lights lights;
private DVDPlayer dvdPlayer;
public void watchMovie(String movieName) {
lights.dimLights(30);
projector.on();
projector.setInput(dvdPlayer);
audioSystem.on();
audioSystem.setVolume(50);
dvdPlayer.play(movieName);
}
public void endMovie() {
dvdPlayer.stop();
audioSystem.off();
projector.off();
lights.brightLights();
}
}
// Использование — один вызов вместо множества
HomeTheaterFacade homeTheater = new HomeTheaterFacade(...);
homeTheater.watchMovie("Interstellar");
Proxy (Прокси)
Контролируемый доступ к другому объекту.
public interface Database {
void query(String sql);
}
public class RealDatabase implements Database {
@Override
public void query(String sql) {
System.out.println("Executing: " + sql);
}
}
public class DatabaseProxy implements Database {
private RealDatabase realDatabase;
private String username;
public DatabaseProxy(String username) {
this.username = username;
}
@Override
public void query(String sql) {
// Логирование и авторизация
System.out.println("User: " + username + " executing query");
if (!hasAccess(sql)) {
throw new SecurityException("Access denied");
}
if (realDatabase == null) {
realDatabase = new RealDatabase();
}
realDatabase.query(sql);
}
private boolean hasAccess(String sql) {
// Проверка прав доступа
return true;
}
}
3. Поведенческие паттерны (Behavioral Patterns)
Эти паттерны определяют взаимодействие между объектами.
Strategy (Стратегия)
Выбор алгоритма во время выполнения.
public interface SortingStrategy {
void sort(int[] array);
}
public class QuickSort implements SortingStrategy {
@Override
public void sort(int[] array) {
// Быстрая сортировка
}
}
public class MergeSort implements SortingStrategy {
@Override
public void sort(int[] array) {
// Сортировка слиянием
}
}
public class Sorter {
private SortingStrategy strategy;
public Sorter(SortingStrategy strategy) {
this.strategy = strategy;
}
public void sort(int[] array) {
strategy.sort(array);
}
}
// Использование
Sorter sorter = new Sorter(new QuickSort());
sorter.sort(numbers);
// Смена стратегии
sorter = new Sorter(new MergeSort());
Observer (Наблюдатель)
Оповещение множества объектов об изменениях.
public interface Observer {
void update(String message);
}
public class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
public class EmailNotifier implements Observer {
@Override
public void update(String message) {
System.out.println("Email: " + message);
}
}
public class SMSNotifier implements Observer {
@Override
public void update(String message) {
System.out.println("SMS: " + message);
}
}
// Использование
Subject subject = new Subject();
subject.attach(new EmailNotifier());
subject.attach(new SMSNotifier());
subject.notifyObservers("Important news!");
Command (Команда)
Инкапсуляция запроса как объекта.
public interface Command {
void execute();
void undo();
}
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
@Override
public void undo() {
light.off();
}
}
public class RemoteControl {
private List<Command> commandHistory = new ArrayList<>();
public void execute(Command command) {
command.execute();
commandHistory.add(command);
}
public void undo() {
if (!commandHistory.isEmpty()) {
Command lastCommand = commandHistory.remove(commandHistory.size() - 1);
lastCommand.undo();
}
}
}
State (Состояние)
Изменение поведения в зависимости от состояния.
public interface State {
void insertMoney(VendingMachine machine, double amount);
void selectProduct(VendingMachine machine, String product);
}
public class IdleState implements State {
@Override
public void insertMoney(VendingMachine machine, double amount) {
machine.setBalance(machine.getBalance() + amount);
machine.setState(new MoneyInsertedState());
}
@Override
public void selectProduct(VendingMachine machine, String product) {
System.out.println("Please insert money first");
}
}
public class MoneyInsertedState implements State {
@Override
public void selectProduct(VendingMachine machine, String product) {
// Логика выдачи товара
}
}
Template Method (Шаблонный метод)
Определение скелета алгоритма в базовом классе.
public abstract class CoffeeRecipe {
public void prepareCoffee() {
boilWater();
brewCoffee();
pourIntoCup();
addCondiments(); // Может быть переопределено
}
private void boilWater() {
System.out.println("Boiling water");
}
protected abstract void brewCoffee();
private void pourIntoCup() {
System.out.println("Pouring into cup");
}
protected void addCondiments() {
// По умолчанию ничего
}
}
public class AmericanoCoffee extends CoffeeRecipe {
@Override
protected void brewCoffee() {
System.out.println("Brewing americano");
}
}
public class ItalianCoffee extends CoffeeRecipe {
@Override
protected void brewCoffee() {
System.out.println("Brewing espresso");
}
@Override
protected void addCondiments() {
System.out.println("Adding crema");
}
}
Рекомендации по выбору паттернов
- Singleton — глобальные ресурсы (конфиг, логгер, БД)
- Factory — создание объектов разных типов
- Builder — сложные объекты с множеством параметров
- Decorator — добавление функциональности динамически
- Strategy — различные алгоритмы, выбираемые во время выполнения
- Observer — loose coupling между компонентами
- Command — очереди операций, undo/redo
- State — изменение поведения в зависимости от состояния
Паттерны — это не панацея. Не переусложняй код неоправданными паттернами. Используй их когда это действительно упрощает архитектуру.