- Chain of Responsibility 는 여러 가지의 기능을 개별 class 에서 구현하고, 이를 연결, 연결, 연결 해서, client 에서 필요한 chain 을 연결해서 쓸 수 있게 한다.
- netty 에서 여러가지 request handler 를 연결해서 쓰는것이 바로 이 패턴이다.
- 모든 class 는 당연히 동일한 interface 를 구현하고, next chain 으로 넘길지, 바로 처리할지를 구분 할 수 있다.
- runtime 동적으로 필요한 체인을 원하는 순서대로 연결해서 쓸 수 있고, 잘 쪼개지면 좋은 설계가 된다.
- 아래 예제는 Middleware 라는 abstract class 안에, Middleware next 라는, 다음 handler 를 담기 위한 변수가 있고,
- abstract boolean check() 라는 method 가 각각 구현체에서 구현할 함수이다.
- linkWith 라는 생성자처럼 생긴 public 함수는, next handler 를 받고 그걸 돌려준다.
- abstract check 를 구현하므로, 각각의 handler 는 동일한 parameter 를 받는다.
- checkNext 함수는 각각의 구현된 check 함수에서 쓰이며, 다음 handler 로 넘길지, 끝낼지를 결정할 수 있다.
public abstract class Middleware {
private Middleware next;
public Middleware linkWith(Middleware next) {
this.next = next;
return next;
}
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);
}
}
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();
}
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);
}
}
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);
}
}
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);
}
}
public class Server {
private Map<String, String> users = new HashMap<>();
private Middleware middleware;
public void setMiddleware(Middleware middleware) {
this.middleware = middleware;
}
public boolean logIn(String email, String password) {
if (middleware.check(email, password)) {
System.out.println("Authorization have been successful!");
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);
}
}
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");
Middleware middleware = new ThrottlingMiddleware(2);
middleware.linkWith(new UserExistsMiddleware(server))
.linkWith(new RoleCheckMiddleware());
server.setMiddleware(middleware);
}
}
Comments
Post a Comment