Готовые решения для гениального кода: Путеводитель по паттернам проектирования GoF на примере Java
Что такое паттерны проектирования GoF?
Паттерны проектирования — это повторно используемые решения типичных проблем проектирования, встречающихся в программировании. Авторы — Эрих Гамма, Ричард Хелм, Ральф Джонсон и Джон Влиссидес (Gang of Four) — представили систематизированный подход к проектированию программного обеспечения, ставший эталонным для поколения разработчиков.
Паттерны GoF полезны, так как решают стандартные задачи проектирования, экономя время на придумывание решений заново. Они способствуют повторному использованию опыта и улучшению качества кода.
Какие существуют паттерны GoF и зачем они нужны?
Паттерны GoF традиционно делятся на три категории:
1. Creational (создание объектов)
✅ Решают вопросы инициализации и создания объектов.
— Singleton (Одиночка)
Гарантирует существование ровно одного экземпляра класса и предоставляет глобальную точку доступа к нему. Пример реализации на Java:
public final class Logger {
private static volatile Logger instance = null;
// Private constructor prevents instantiation from outside
private Logger() {}
public static Logger getInstance() {
if (instance == null) { // Double-check locking pattern
synchronized (Logger.class) {
if (instance == null) {
instance = new Logger();
}
}
}
return instance;
}
} — Factory Method (Фабричный метод)
Делегирует создание объектов подклассам. Пример:
abstract class Button {
abstract void render();
}
class WinButton extends Button {
@Override
void render() {
System.out.println("Rendering Windows button");
}
}
class MacButton extends Button {
@Override
void render() {
System.out.println("Rendering macOS button");
}
}
// Client uses factory method to create buttons
class Dialog {
protected abstract Button createButton();
public void renderDialog() {
Button btn = this.createButton(); // Factory method invocation
btn.render();
}
}
class WinDialog extends Dialog {
@Override
protected Button createButton() {
return new WinButton();
}
}
class MacDialog extends Dialog {
@Override
protected Button createButton() {
return new MacButton();
}
}
2. Structural (структурная организация)
✅ Организует связи между объектами и упрощает их интеграцию и модификацию.
— Adapter (Адаптер)
Преобразует интерфейс одного класса в требуемый клиентами. Пример:
interface Printable {
void print();
}
class TextDocument implements Printable {
@Override
public void print() {
System.out.println("Printing document...");
}
}
// Legacy system has incompatible interface
class OldPrinter {
public void legacyPrint(Object obj) {
System.out.println("Legacy printing mechanism...");
}
}
// Adapter bridges old printer with modern documents
class PrinterAdapter implements Printable {
private OldPrinter printer;
public PrinterAdapter(OldPrinter p) {
this.printer = p;
}
@Override
public void print() {
printer.legacyPrint(this);
}
} — Facade (Фасад)
Упрощает сложный интерфейс подсистемы. Пример:
class Computer {
boolean cpuRunning = false;
boolean hddSpinning = false;
void startCPU() {
cpuRunning = true;
}
void spinHDD() {
hddSpinning = true;
}
void halt() {
cpuRunning = false;
hddSpinning = false;
}
}
// Facade simplifies starting/shutting down process
class ComputerFacade {
private Computer comp;
public ComputerFacade(Computer c) {
this.comp = c;
}
public void turnOn() {
comp.startCPU();
comp.spinHDD();
}
public void shutDown() {
comp.halt();
}
}
3. Behavioral (поведенческие модели)
✅ Управляют взаимодействием между объектами и координацией действий.
— Observer (Наблюдатель)
Оповещает наблюдателей при изменении состояния. Пример:
interface Observer {
void update(String message);
}
class Subject {
List<Observer> observers = new ArrayList<>();
String state;
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer o : observers)
o.update(state);
}
public void setState(String s) {
this.state = s;
notifyObservers();
}
}
class ConcreteObserver implements Observer {
@Override
public void update(String msg) {
System.out.println("Received update: " + msg);
}
}
— Command (Команда)
Инкапсулирует запрос в объект, обеспечивая возможность параметризовать действия. Пример:
interface Command {
void execute();
}
class Light {
public void switchOn() {
System.out.println("Light turned ON!");
}
public void switchOff() {
System.out.println("Light turned OFF!");
}
}
class TurnOnCommand implements Command {
private Light light;
public TurnOnCommand(Light l) {
this.light = l;
}
@Override
public void execute() {
light.switchOn();
}
}
class TurnOffCommand implements Command {
private Light light;
public TurnOffCommand(Light l) {
this.light = l;
}
@Override
public void execute() {
light.switchOff();
}
}
class RemoteController {
private Command command;
public void setCommand(Command cmd) {
this.command = cmd;
}
public void pressButton() {
command.execute();
}
}
Применение паттернов GoF — верный путь к профессиональному росту и созданию высококачественного, масштабируемого и легко сопровождаемого кода. Используйте готовые рецепты для проектирования, уменьшайте дублирование и повышайте качество своего кода!