 
                Ланцюжок обов'язків на Java
Ланцюжок обов’язків — це поведінковий патерн, що дозволяє передавати запит ланцюжком потенційних обробників до тих пір, поки один з них не обробить його.
Позбавляє від жорсткої прив’язки відправника запиту до одержувача, дозволяючи динамічно вибудовувати ланцюг з різних обробників.
Складність:
Популярність:
Застосування: Патерн зустрічається в Java не так вже й часто, оскільки для його застосування потрібен ланцюг об’єктів, наприклад, зв’язаний список.
Сфера застосування ланцюжка обов’язків — різноманітні обробники подій, послідовні перевірки доступу та інше.
Приклади Ланцюжка обов’язків в стандартних бібліотеках Java:
Ознаки застосування патерна: Ланцюжок обов’язків можна визначити за списками обробників або перевірок, через які пропускаються запити. Особливо, якщо порядок проходження обробників є важливим.
Шари авторизації та аутентифікації користувачів
Цей приклад показує як дані користувача проходять послідовну аутентифікацію через багато обробників, зв’язаних в один ланцюг.
Цей приклад відрізняється від канонічної версії тим, що перевірка припиняється, якщо черговий обробник не може обробити запит. В класичному варіанті проходження ланцюжком закінчується відразу, як тільки знаходиться елемент ланцюга, що може обробити запит. Просто знайте, що Концептуальний приклад від цього не змінюється, а код відрізняється тільки умовою виходу з ланцюга.
middleware
middleware/Middleware.java: Базовий клас перевірок
package refactoring_guru.chain_of_responsibility.example.middleware;
/**
 * Base middleware class.
 */
public abstract class Middleware {
    private Middleware next;
    /**
     * Builds chains of middleware objects.
     */
    public static Middleware link(Middleware first, Middleware... chain) {
        Middleware head = first;
        for (Middleware nextInChain: chain) {
            head.next = nextInChain;
            head = nextInChain;
        }
        return first;
    }
    /**
     * Subclasses will implement this method with concrete checks.
     */
    public abstract boolean check(String email, String password);
    /**
     * Runs check on the next object in chain or ends traversing if we're in
     * last object in chain.
     */
    protected boolean checkNext(String email, String password) {
        if (next == null) {
            return true;
        }
        return next.check(email, password);
    }
}
middleware/ThrottlingMiddleware.java: Перевірка на ліміт запитів
package refactoring_guru.chain_of_responsibility.example.middleware;
/**
 * ConcreteHandler. Checks whether there are too many failed login requests.
 */
public class ThrottlingMiddleware extends Middleware {
    private int requestPerMinute;
    private int request;
    private long currentTime;
    public ThrottlingMiddleware(int requestPerMinute) {
        this.requestPerMinute = requestPerMinute;
        this.currentTime = System.currentTimeMillis();
    }
    /**
     * Please, not that checkNext() call can be inserted both in the beginning
     * of this method and in the end.
     *
     * This gives much more flexibility than a simple loop over all middleware
     * objects. For instance, an element of a chain can change the order of
     * checks by running its check after all other checks.
     */
    public boolean check(String email, String password) {
        if (System.currentTimeMillis() > currentTime + 60_000) {
            request = 0;
            currentTime = System.currentTimeMillis();
        }
        request++;
        
        if (request > requestPerMinute) {
            System.out.println("Request limit exceeded!");
            Thread.currentThread().stop();
        }
        return checkNext(email, password);
    }
}
middleware/UserExistsMiddleware.java: Перевірка пароля
package refactoring_guru.chain_of_responsibility.example.middleware;
import refactoring_guru.chain_of_responsibility.example.server.Server;
/**
 * ConcreteHandler. Checks whether a user with the given credentials exists.
 */
public class UserExistsMiddleware extends Middleware {
    private Server server;
    public UserExistsMiddleware(Server server) {
        this.server = server;
    }
    public boolean check(String email, String password) {
        if (!server.hasEmail(email)) {
            System.out.println("This email is not registered!");
            return false;
        }
        if (!server.isValidPassword(email, password)) {
            System.out.println("Wrong password!");
            return false;
        }
        return checkNext(email, password);
    }
}
middleware/RoleCheckMiddleware.java: Перевірка ролі
package refactoring_guru.chain_of_responsibility.example.middleware;
/**
 * ConcreteHandler. Checks a user's role.
 */
public class RoleCheckMiddleware extends Middleware {
    public boolean check(String email, String password) {
        if (email.equals("admin@example.com")) {
            System.out.println("Hello, admin!");
            return true;
        }
        System.out.println("Hello, user!");
        return checkNext(email, password);
    }
}
server
server/Server.java: Сервер, на який заходимо
package refactoring_guru.chain_of_responsibility.example.server;
import refactoring_guru.chain_of_responsibility.example.middleware.Middleware;
import java.util.HashMap;
import java.util.Map;
/**
 * Server class.
 */
public class Server {
    private Map<String, String> users = new HashMap<>();
    private Middleware middleware;
    /**
     * Client passes a chain of object to server. This improves flexibility and
     * makes testing the server class easier.
     */
    public void setMiddleware(Middleware middleware) {
        this.middleware = middleware;
    }
    /**
     * Server gets email and password from client and sends the authorization
     * request to the chain.
     */
    public boolean logIn(String email, String password) {
        if (middleware.check(email, password)) {
            System.out.println("Authorization have been successful!");
            // Do something useful here for authorized users.
            return true;
        }
        return false;
    }
    public void register(String email, String password) {
        users.put(email, password);
    }
    public boolean hasEmail(String email) {
        return users.containsKey(email);
    }
    public boolean isValidPassword(String email, String password) {
        return users.get(email).equals(password);
    }
}
Demo.java: Клієнтський код
package refactoring_guru.chain_of_responsibility.example;
import refactoring_guru.chain_of_responsibility.example.middleware.Middleware;
import refactoring_guru.chain_of_responsibility.example.middleware.RoleCheckMiddleware;
import refactoring_guru.chain_of_responsibility.example.middleware.ThrottlingMiddleware;
import refactoring_guru.chain_of_responsibility.example.middleware.UserExistsMiddleware;
import refactoring_guru.chain_of_responsibility.example.server.Server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
 * Demo class. Everything comes together here.
 */
public class Demo {
    private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    private static Server server;
    private static void init() {
        server = new Server();
        server.register("admin@example.com", "admin_pass");
        server.register("user@example.com", "user_pass");
        // All checks are linked. Client can build various chains using the same
        // components.
        Middleware middleware = Middleware.link(
            new ThrottlingMiddleware(2),
            new UserExistsMiddleware(server),
            new RoleCheckMiddleware()
        );
        // Server gets a chain from client code.
        server.setMiddleware(middleware);
    }
    public static void main(String[] args) throws IOException {
        init();
        boolean success;
        do {
            System.out.print("Enter email: ");
            String email = reader.readLine();
            System.out.print("Input password: ");
            String password = reader.readLine();
            success = server.logIn(email, password);
        } while (!success);
    }
}
OutputDemo.txt: Результат виконання
Enter email: admin@example.com
Input password: admin_pass
Hello, admin!
Authorization have been successful!
Enter email: wrong@example.com
Input password: wrong_pass
This email is not registered!
Enter email: wrong@example.com
Input password: wrong_pass
This email is not registered!
Enter email: wrong@example.com
Input password: wrong_pass
Request limit exceeded!