В: Что такое шаблон проектирования в Java?

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

Вопрос: разница между шаблоном проектирования и архитектурным шаблоном

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

Шаблоны проектирования — это решения общих проблем проектирования программного обеспечения, которые неоднократно встречаются при разработке программного обеспечения. Они предоставляют многоразовые и гибкие решения этих проблем, которые помогают улучшить качество разрабатываемого программного обеспечения. Шаблоны проектирования находятся на более низком уровне абстракции и ориентированы на решение проблем проектирования в конкретном контексте, таком как объектно-ориентированное проектирование.

С другой стороны, архитектурные шаблоны представляют собой абстракции более высокого уровня, которые обеспечивают основу для общей структуры приложения. Они определяют основные компоненты, отношения и шаблоны взаимодействия, составляющие архитектуру приложения. Они ориентированы на общую организацию приложения и взаимодействие между его компонентами. Архитектурные шаблоны имеют более широкий охват, чем шаблоны проектирования, и они касаются таких вопросов, как масштабируемость, ремонтопригодность и безопасность.

В: Какие существуют типы шаблонов проектирования в Java?

О. В Java существует три типа шаблонов проектирования: творческие, структурные и поведенческие.

  1. Шаблоны создания. Эти шаблоны фокусируются на процессе создания объектов и предоставляют способы создания объектов гибким и многоразовым способом. Примеры шаблонов создания в Java включают Singleton, Factory Method, Abstract Factory, Builder и Prototype.
  2. Структурные шаблоны. Эти шаблоны фокусируются на композиции классов и объектов для формирования более крупных структур. Они предоставляют способы определения отношений между объектами, упрощают проектирование сложных систем и делают системы более расширяемыми. Примеры структурных паттернов в Java включают адаптер, мост, композит, декоратор, фасад, приспособленец и прокси.
  3. Поведенческие паттерны. Эти паттерны сосредоточены на взаимодействии между объектами и распределении ответственности между ними. Они обеспечивают способы управления коммуникациями, повышают гибкость и упрощают проектирование сложных систем. Примеры поведенческих паттернов в Java включают цепочку ответственности, команду, интерпретатор, итератор, посредник, сувенир, наблюдатель, состояние, стратегию, метод шаблона и посетителя.

В: Что такое шаблон проектирования Singleton в Java?

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

Чтобы реализовать шаблон Singleton в Java, вы можете выполнить следующие шаги:

  1. Создайте закрытый конструктор для класса, чтобы он не мог быть создан вне класса.
  2. Объявите частную статическую переменную, которая будет содержать единственный экземпляр класса.
  3. Создайте общедоступный статический метод, который будет возвращать единственный экземпляр класса. Этот метод должен проверять, был ли уже создан экземпляр, и если нет, создать его.
  4. Если несколько потоков могут одновременно обращаться к экземпляру Singleton, рассмотрите возможность синхронизации метода getInstance(), чтобы предотвратить проблемы с одновременным доступом.

Вот пример того, как реализовать шаблон Singleton в Java:

public class Singleton {
    private static Singleton instance = null;

    private Singleton() {
        // private constructor
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

В этом примере класс Singleton имеет частный конструктор и частную статическую переменную экземпляра. Метод getInstance() используется для получения единственного экземпляра класса. Если экземпляр еще не создан, он создает новый экземпляр и возвращает его. Если экземпляр уже создан, он просто возвращает существующий экземпляр. Синхронизированное ключевое слово используется, чтобы гарантировать, что только один поток может получить доступ к методу getInstance() за раз.

В: Что такое шаблон проектирования Factory Method в Java?

О: Шаблон Factory Method — это порождающий шаблон проектирования, который позволяет создавать объекты без указания их точного класса. Он определяет интерфейс для создания объектов, но позволяет подклассам решать, какой класс создавать. Этот шаблон полезен, когда вам нужно отделить создание объектов от деталей реализации.

Чтобы реализовать шаблон Factory Method в Java, вы можете выполнить следующие шаги:

  1. Определите интерфейс или абстрактный класс, который объявляет фабричный метод для создания объектов.
  2. Создайте конкретные классы, реализующие интерфейс или абстрактный класс, и предоставьте собственную реализацию фабричного метода.
  3. Определите клиентский класс, который использует фабричный метод для создания объектов, не зная их точного класса.

Вот пример того, как реализовать шаблон Factory Method в Java:

public interface Animal {
    void speak();
}

public class Dog implements Animal {
    @Override
    public void speak() {
        System.out.println("Dog says: Bow Wow!");
    }
}

public class Cat implements Animal {
    @Override
    public void speak() {
        System.out.println("Cat says: Meow!");
    }
}

public interface AnimalFactory {
    Animal createAnimal();
}

public class DogFactory implements AnimalFactory {
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}

public class CatFactory implements AnimalFactory {
    @Override
    public Animal createAnimal() {
        return new Cat();
    }
}

public class AnimalClient {
    public static void main(String[] args) {
        AnimalFactory dogFactory = new DogFactory();
        Animal dog = dogFactory.createAnimal();
        dog.speak();

        AnimalFactory catFactory = new CatFactory();
        Animal cat = catFactory.createAnimal();
        cat.speak();
    }
}

В этом примере интерфейс Animal определяет метод speak(), реализованный классами Dog и Cat. Интерфейс AnimalFactory объявляет метод createAnimal(), который реализуется классами DogFactory и CatFactory. Класс AnimalClient использует фабричные методы для создания экземпляров классов Dog и Cat, не зная их точного класса. Это позволяет отделить клиентский код от деталей реализации классов.

В: Что такое шаблон проектирования Observer в Java?

О. Шаблон Observer — это поведенческий шаблон проектирования, определяющий зависимость «один ко многим» между объектами, так что при изменении состояния одного объекта все его зависимые объекты получают уведомление и автоматически обновляются. Этот шаблон используется, когда необходимо, чтобы несколько объектов были уведомлены и обновлены об изменениях в одном объекте.

Чтобы реализовать шаблон Observer в Java, вы можете выполнить следующие шаги:

  1. Определите интерфейс для объектов Observer, указывающий методы, которые будут вызываться при изменении состояния наблюдаемого объекта.
  2. Определите интерфейс для объекта Subject (наблюдаемый), который позволяет объектам Observer регистрировать, удалять и уведомлять их об изменениях.
  3. Создайте конкретные классы Observer, которые реализуют интерфейс Observer и предоставляют собственную реализацию метода обновления.
  4. Создайте конкретный класс Subject, реализующий интерфейс Subject и поддерживающий список зарегистрированных объектов Observer. Этот класс также предоставляет методы для изменения состояния объекта, что запускает уведомления для всех зарегистрированных наблюдателей.

Вот пример того, как реализовать шаблон Observer в Java:

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

// Observer interface
interface Observer {
    void update(int value);
}

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

// Concrete Observer class
class ConcreteObserver implements Observer {
    @Override
    public void update(int value) {
        System.out.println("Value changed to " + value);
    }
}

// Concrete Subject class
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private int value;

    public void setValue(int value) {
        this.value = value;
        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(value);
        }
    }
}

// Client code
public class ObserverDemo {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();

        // Create observers and register them
        Observer observer1 = new ConcreteObserver();
        subject.registerObserver(observer1);

        Observer observer2 = new ConcreteObserver();
        subject.registerObserver(observer2);

        // Modify the value of the subject, which triggers notifications to all observers
        subject.setValue(10);

        // Remove one observer and modify the value again
        subject.removeObserver(observer1);
        subject.setValue(20);
    }
}

В этом примере интерфейс Observer указывает метод обновления, реализованный классом ConcreteObserver. Интерфейс Subject определяет методы registerObserver, removeObserver и notifyObservers, которые реализованы классом ConcreteSubject. Код клиента создает объекты ConcreteObserver и регистрирует их с помощью объекта ConcreteSubject. Когда значение объекта ConcreteSubject изменяется, оно запускает уведомления для всех зарегистрированных объектов ConcreteObserver. Клиентский код также может в любой момент удалить наблюдателей из объекта ConcreteSubject.

В: Что такое шаблон проектирования адаптера в Java?

О: Шаблон адаптера — это структурный шаблон проектирования, который позволяет несовместимым интерфейсам работать вместе. Он преобразует интерфейс класса в другой интерфейс, ожидаемый клиентами. Этот шаблон полезен, когда есть классы с несовместимыми интерфейсами, которые нельзя использовать вместе, но их необходимо интегрировать.

Чтобы реализовать шаблон адаптера в Java, вы можете выполнить следующие шаги:

  1. Определите целевой интерфейс, который клиент ожидает использовать.
  2. Определите существующий интерфейс, который необходимо адаптировать для соответствия целевому интерфейсу.
  3. Создайте класс адаптера, который реализует целевой интерфейс и содержит экземпляр существующего интерфейса.
  4. Реализуйте методы целевого интерфейса в классе адаптера, вызвав соответствующие методы существующего экземпляра интерфейса.

Вот пример того, как реализовать шаблон адаптера в Java:

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

// Existing interface
interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

// Existing class that implements the AdvancedMediaPlayer interface
class VlcPlayer implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file. Name: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {
        // do nothing
    }
}

// Existing class that implements the AdvancedMediaPlayer interface
class Mp4Player implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        // do nothing
    }

    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file. Name: " + fileName);
    }
}

// Adapter class that implements the MediaPlayer interface and contains an instance of the AdvancedMediaPlayer interface
class MediaAdapter implements MediaPlayer {
    private AdvancedMediaPlayer advancedMediaPlayer;

    public MediaAdapter(String audioType) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMediaPlayer = new VlcPlayer();
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMediaPlayer = new Mp4Player();
        }
    }

    @Override
    public void play(String audioType, String fileName) {
        if (audioType.equalsIgnoreCase("vlc")) {
            advancedMediaPlayer.playVlc(fileName);
        } else if (audioType.equalsIgnoreCase("mp4")) {
            advancedMediaPlayer.playMp4(fileName);
        }
    }
}

// Client code
public class AdapterDemo {
    public static void main(String[] args) {
        MediaPlayer mediaPlayer = new MediaAdapter("mp4");
        mediaPlayer.play("mp4", "movie.mp4");

        mediaPlayer = new MediaAdapter("vlc");
        mediaPlayer.play("vlc", "song.vlc");
    }
}

В этом примере интерфейс MediaPlayer является целевым интерфейсом, который клиент ожидает использовать. Интерфейс AdvancedMediaPlayer — это существующий интерфейс, который необходимо адаптировать. Классы VlcPlayer и Mp4Player реализуют интерфейс AdvancedMediaPlayer. Класс MediaAdapter реализует интерфейс MediaPlayer и содержит экземпляр интерфейса AdvancedMediaPlayer. Он адаптирует интерфейс AdvancedMediaPlayer к интерфейсу MediaPlayer, реализуя метод воспроизведения интерфейса MediaPlayer и вызывая соответствующие методы экземпляра AdvancedMediaPlayer. Клиентский код создает экземпляры класса MediaAdapter и использует их для воспроизведения мультимедийных файлов разных типов.

В: Что такое шаблон проектирования Decorator в Java?

О: Шаблон Decorator — это шаблон структурного проектирования, который позволяет динамически добавлять новое поведение к существующему объекту, не изменяя его структуру. Он включает в себя создание класса декоратора, который обертывает исходный объект и добавляет к нему новые функции.

Чтобы реализовать шаблон Decorator в Java, вы можете выполнить следующие шаги:

  1. Создайте интерфейс или абстрактный класс, определяющий методы, которые должны быть реализованы как исходным объектом, так и декоратором.
  2. Создайте конкретный класс, реализующий интерфейс или абстрактный класс и представляющий исходный объект.
  3. Создайте класс декоратора, который реализует тот же интерфейс или абстрактный класс и содержит экземпляр исходного объекта.
  4. Реализуйте методы интерфейса или абстрактного класса в классе декоратора, вызвав соответствующие методы исходного экземпляра объекта и добавив новую функциональность.

Вот пример того, как реализовать шаблон Decorator в Java:

// Interface or abstract class
interface Car {
    void assemble();
}

// Concrete class that implements the Car interface
class BasicCar implements Car {
    @Override
    public void assemble() {
        System.out.println("Basic Car.");
    }
}

// Decorator class that implements the Car interface and contains an instance of the Car interface
class CarDecorator implements Car {
    protected Car car;

    public CarDecorator(Car car) {
        this.car = car;
    }

    @Override
    public void assemble() {
        car.assemble();
    }
}

// Concrete decorator class that adds new functionality to the original object
class SportsCarDecorator extends CarDecorator {
    public SportsCarDecorator(Car car) {
        super(car);
    }

    @Override
    public void assemble() {
        super.assemble();
        System.out.println("Adding features of Sports Car.");
    }
}

// Client code
public class DecoratorDemo {
    public static void main(String[] args) {
        Car basicCar = new BasicCar();
        basicCar.assemble();

        Car sportsCar = new SportsCarDecorator(new BasicCar());
        sportsCar.assemble();
    }
}

В этом примере интерфейс Car — это интерфейс, который будут реализовывать как исходный объект, так и декоратор. Класс BasicCar реализует интерфейс Car и представляет исходный объект. Класс CarDecorator — это класс-декоратор, который реализует интерфейс Car и содержит экземпляр интерфейса Car. Класс SportsCarDecorator — это конкретный класс декоратора, добавляющий новые функциональные возможности исходному объекту. Код клиента создает экземпляры классов BasicCar и SportsCarDecorator и использует их для сборки автомобилей. Когда спортивный автомобиль собран, SportsCarDecorator добавляет новые функции к базовому автомобилю, вызывая метод сборки экземпляра BasicCar и добавляя новые функции.

В: Что такое шаблон проектирования Command в Java?

О: Шаблон Command — это поведенческий шаблон проектирования, который инкапсулирует запрос в виде объекта, что позволяет нам параметризовать клиентов с различными запросами, ставить в очередь или регистрировать запросы и поддерживать операции, которые нельзя выполнить. Он включает в себя создание интерфейса Command или абстрактного класса, определяющего метод выполнения, и конкретных классов, реализующих интерфейс Command и представляющих различные команды.

Чтобы реализовать шаблон Command в Java, вы можете выполнить следующие шаги:

  1. Создайте командный интерфейс или абстрактный класс, определяющий метод выполнения.
  2. Создайте конкретные классы, реализующие интерфейс Command и представляющие различные команды. Эти классы должны содержать ссылку на объект-приемник, который будет выполнять команду.
  3. Создайте класс вызывающего объекта, который будет выполнять команды, вызывая их метод execute.
  4. Клиентский код должен создавать экземпляры конкретных классов команд и передавать их классу вызывающей стороны.

Вот пример того, как реализовать шаблон Command в Java:

// Command interface
interface Command {
    void execute();
}

// Concrete command classes
class LightOnCommand implements Command {
    private Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOn();
    }
}

class LightOffCommand implements Command {
    private Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.turnOff();
    }
}

// Receiver class
class Light {
    public void turnOn() {
        System.out.println("Light turned on");
    }

    public void turnOff() {
        System.out.println("Light turned off");
    }
}

// Invoker class
class RemoteControl {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void pressButton() {
        command.execute();
    }
}

// Client code
public class CommandDemo {
    public static void main(String[] args) {
        Light light = new Light();
        Command lightOn = new LightOnCommand(light);
        Command lightOff = new LightOffCommand(light);

        RemoteControl remoteControl = new RemoteControl();
        remoteControl.setCommand(lightOn);
        remoteControl.pressButton();

        remoteControl.setCommand(lightOff);
        remoteControl.pressButton();
    }
}

Командный интерфейс определяет метод выполнения, который будет реализован конкретными командными классами. Классы LightOnCommand и LightOffCommand — это конкретные классы команд, которые реализуют интерфейс Command и представляют разные команды. Они содержат ссылку на объект Light, который будет выполнять команду. Класс Light — это класс приемника, который содержит реальную реализацию включения и выключения света. Класс RemoteControl — это класс-вызов, который будет выполнять команды, вызывая их метод execute. Наконец, клиентский код создает экземпляры конкретных классов Command и передает их классу вызывающей стороны. Когда кнопка на пульте дистанционного управления нажата, инициатор вызывает метод execute соответствующего объекта Command, который, в свою очередь, вызывает соответствующий метод объекта-получателя.

В: Что такое шаблон проектирования Iterator в Java?

О: Шаблон Iterator — это поведенческий шаблон проектирования, который обеспечивает способ последовательного доступа к элементам агрегатного объекта (например, коллекции), не раскрывая его базовое представление. Он включает в себя создание интерфейса Iterator или абстрактного класса, определяющего методы доступа к элементам агрегатного объекта, и конкретных классов, реализующих интерфейс Iterator и представляющих различные типы итераторов.

Чтобы реализовать шаблон Iterator в Java, вы можете выполнить следующие шаги:

  1. Создайте интерфейс Iterator или абстрактный класс, определяющий методы доступа к элементам агрегатного объекта. Как правило, эти методы включают hasNext() для проверки наличия дополнительных элементов и next() для возврата следующего элемента.
  2. Создайте конкретные классы, реализующие интерфейс Iterator и представляющие различные типы итераторов. Эти классы должны содержать ссылку на агрегатный объект, по которому они перебираются.
  3. Создайте конкретный агрегатный класс, который реализует интерфейс Iterable или определяет метод, возвращающий объект Iterator. Этот метод должен создавать и возвращать экземпляр соответствующего класса Iterator.
  4. Клиентский код может использовать итератор для доступа к элементам агрегатного объекта.

Вот пример того, как реализовать шаблон Iterator в Java:

// Iterator interface
interface Iterator<T> {
    boolean hasNext();
    T next();
}

// Concrete iterator class
class ArrayIterator<T> implements Iterator<T> {
    private T[] array;
    private int currentIndex;

    public ArrayIterator(T[] array) {
        this.array = array;
        this.currentIndex = 0;
    }

    public boolean hasNext() {
        return currentIndex < array.length;
    }

    public T next() {
        return array[currentIndex++];
    }
}

// Aggregate class
class Array<T> implements Iterable<T> {
    private T[] array;

    public Array(T[] array) {
        this.array = array;
    }

    public Iterator<T> iterator() {
        return new ArrayIterator<T>(array);
    }
}

// Client code
public class IteratorDemo {
    public static void main(String[] args) {
        Integer[] array = {1, 2, 3, 4, 5};
        Array<Integer> integerArray = new Array<Integer>(array);

        Iterator<Integer> iterator = integerArray.iterator();
        while (iterator.hasNext()) {
            Integer element = iterator.next();
            System.out.println(element);
        }
    }
}

В этом примере интерфейс Iterator определяет методы hasNext() и next(), которые будут реализованы конкретными классами итераторов. Класс ArrayIterator — это конкретный класс итератора, реализующий интерфейс Iterator и предоставляющий доступ к элементам массива. Класс Array — это агрегатный класс, определяющий метод, возвращающий объект Iterator. Клиентский код создает экземпляр класса Array и использует его итератор для доступа к элементам массива. Итератор выполняет итерацию по массиву и возвращает каждый элемент.

В: Что такое шаблон проектирования "Метод шаблона" в Java?

О: Шаблон шаблонного метода — это поведенческий шаблон проектирования, который позволяет определить скелет алгоритма в базовом классе и делегировать некоторые шаги алгоритма подклассам. Он включает создание абстрактного базового класса, определяющего шаблонный метод, который вызывает другие методы (абстрактные или конкретные) для выполнения определенных шагов алгоритма.

Чтобы реализовать шаблон метода шаблона в Java, вы можете выполнить следующие шаги:

  1. Создайте абстрактный базовый класс, определяющий метод шаблона. Метод шаблона должен вызывать другие методы (абстрактные или конкретные) для выполнения определенных шагов алгоритма.
  2. Определите абстрактные методы в базовом классе для шагов, которые должны быть реализованы подклассами.
  3. Создайте конкретные подклассы, которые реализуют абстрактные методы, чтобы обеспечить конкретные реализации для шагов.
  4. Клиентский код может создать экземпляр конкретного подкласса и вызвать метод шаблона для выполнения алгоритма.

Вот пример того, как реализовать шаблон Template Method в Java:

// Abstract base class with a template method
abstract class AbstractClass {
    public final void templateMethod() {
        step1();
        step2();
        step3();
    }

    protected abstract void step1();
    protected abstract void step2();
    protected abstract void step3();
}

// Concrete subclass that provides specific implementations for the steps
class ConcreteClass extends AbstractClass {
    protected void step1() {
        System.out.println("ConcreteClass: step 1");
    }

    protected void step2() {
        System.out.println("ConcreteClass: step 2");
    }

    protected void step3() {
        System.out.println("ConcreteClass: step 3");
    }
}

// Client code
public class TemplateMethodDemo {
    public static void main(String[] args) {
        AbstractClass abstractClass = new ConcreteClass();
        abstractClass.templateMethod();
    }
}

В этом примере AbstractClass является абстрактным базовым классом, который определяет шаблонный метод (templateMethod()) и три абстрактных метода (step1(), step2() и step3()), которые представляют определенные шаги алгоритма. ConcreteClass — это конкретный подкласс, предоставляющий конкретные реализации абстрактных методов для определения шагов алгоритма. Клиентский код создает экземпляр ConcreteClass и вызывает метод шаблона для выполнения алгоритма. Метод шаблона вызывает три абстрактных метода в определенном порядке для выполнения алгоритма.

Когда клиентский код вызывает метод шаблона в ConcreteClass, создается следующий вывод:

ConcreteClass: step 1
ConcreteClass: step 2
ConcreteClass: step 3

Это демонстрирует, как шаблон Template Method позволяет вам определять общую структуру алгоритма в базовом классе, позволяя подклассам предоставлять конкретные реализации для некоторых шагов.

Ниже приведены несколько более подробных статей о Java-интервью

Java Interview Вопросы и ответы для любого интервью MNC 2023

Советы и хитрости по программированию на Java

Вопросы и ответы из интервью по Java Collection 2023

Интервью по Java Multi-Threading Вопросы и ответы — 2023