動作設計モード(1)-責任連鎖モード、コマンドモード、割り込みモード


責任連鎖モード


単一責任原則の責任と考えられる.
  public static void main(String[] args) {
        Request request = new Request("무궁화 꽃이 피었습니다.");
        RequestHandler requestHandler = new RequestHandler();
        requestHandler.handler(request);
    }
public class Request {

    private String body;
    public Request(String body) {
        this.body = body;
    }
    public String getBody() {
        return body;
    }
    public void setBody(String body) {
        this.body = body;
    }
}
public class RequestHandler {

    public void handler(Request request) {
        System.out.println(request.getBody());
    }
}
次のコードがある場合は、検証/承認を試みます.
public class RequestHandler {

     public void handler(Request request) {
        System.out.println("인증이 된건가");
        System.out.println("이 핸들러를 사용할수있는 유저인가");
        // 단일책임의 원칙을 위반한다 .

        System.out.println(request.getBody());
    }
}
handlerのコードを最初の方法で変更する方法があります.
しかし、このやり方はSRPに違反している.
public class AuthRequestHandler extends RequestHandler {

    public void handler(Request request) {
        System.out.println("인증이 되었나?");
        System.out.println("이 핸들러를 사용할 수 있는 유저인가?");
        super.handler(request);
    }
}
2つ目は新しいハンドルを作る方法です
  public static void main(String[] args) {
        Request request = new Request("무궁화 꽃이 피었습니다.");
        RequestHandler requestHandler = new AuthRequestHandler(); //변화 
       
        requestHandler.handler(request);
    }
変化するクライアントコード
SRPは保護できますが、まだ問題があるのは
クライアントはAutheRequestHandlerを選択する必要があります.
そして機能が追加されたら
public class LoggingRequestHandler extends RequestHandler {

    @Override
    public void handler(Request request) {
        System.out.println("로깅");
        super.handler(request);
    }
}
次のレコード機能が追加された場合:
 public static void main(String[] args) {
        Request request = new Request("무궁화 꽃이 피었습니다.");
        RequestHandler requestHandler = new LoggingRequestHandler(); //변경
        requestHandler.handler(request);
    }
クライアントはログを再度選択する必要があります.
問題は、クライアントが使用するHandlerを直接理解することです.
記録と認証をしたいならどうしますか?
責任連鎖モードを適用します.

クライアントの目標は、具体的なHandlerタイプを知らないことです.
public abstract class RequestHandler {
    private RequestHandler nextHandler;

    public RequestHandler(RequestHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public void handle(Request request) {
        if (nextHandler != null) {
            nextHandler.handle(request);
        }
    }
}

public class PrintRequestHandler extends RequestHandler{
    public PrintRequestHandler(RequestHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    public void handle(Request request) {
        System.out.println(request.getBody());
        super.handle(request);
    }
}
public class AuthRequestHandler extends RequestHandler{

    public AuthRequestHandler(RequestHandler nextHandler) {
        super(nextHandler);
    }

    @Override
    public void handle(Request request) {
        System.out.println("인증이 되었는가?");
        super.handle(request);
    }
}
public class LoggingRequestHandler extends RequestHandler{

    @Override
    public void handle(Request request) {
        System.out.println("로깅");
        super.handle(request);
    }

    public LoggingRequestHandler(RequestHandler nextHandler) {
        super(nextHandler);
    }
}
public class Client {

    private RequestHandler requestHandler;

    public Client(RequestHandler requestHandler) {
        this.requestHandler = requestHandler;
    }

    public void doWork() {
        Request request = new Request("이번 놀이는 뽑기입니다.");
        requestHandler.handle(request);
    }

    public static void main(String[] args) {
        RequestHandler chain = new AuthRequestHandler(new LoggingRequestHandler(new PrintRequestHandler(null)));
        Client client = new Client(chain);
        client.doWork();
    }
}
すべてのハンドルを通ることもできますし、1つのハンドルだけを起動することもできます.
重要なのは、クライアントがどのハンドルを使用するかを指定する必要はありません.
これは、リクエスト/レスポンスの処理によく使用されるモードです.

長所
  • クライアントコードを変更せずにチェーンに新しいハンドルを追加できます.
  • 各チェーン
  • は自分のすべきことしかしません.
  • 鎖は、様々な方法で構成することができる.
  • 短所
  • をデバッグするのは難しいかもしれません.
  • 使用例
      public static void main(String[] args) {
            Filter filter = new Filter() {
                @Override
                public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                    //  전처리
                    chain.doFilter(request, response);
                    //  후처리
                }
            };
        }
    Sebritフィルタで使用できます.
    要求がサーブレットに到達する前に、複数のフィルタを使用します.
    最終的にはシブリットまで行きます.
    
    @WebFilter(urlPatterns = "/hello")
    public class MyFilter implements Filter {
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            System.out.println("게임에 참하신 여러분 모두 진심으로 환영합니다.");
            chain.doFilter(request, response);
            System.out.println("꽝!");
        }
    }
    @RestController
    public class HelloController {
    
        @GetMapping("/hello")
        public String hello() {
            return "hello";
        }
    }
    
    @ServletComponentScan
    @SpringBootApplication
    public class App {
    
        public static void main(String[] args) {
            SpringApplication.run(App.class, args);
        }
    }

    コマンドモード


    リクエストをカプセル化して呼び出し者(invoker)と受信者を分離
  • 要求を処理する方法が変更されても、発信者のコードは変更されない.
  • public class Light {
    
        private boolean isOn;
    
        public void on() {
            System.out.println("불을 켭니다.");
            this.isOn = true;
        }
    
        public void off() {
            System.out.println("불을 끕니다.");
            this.isOn = false;
        }
    
        public boolean isOn() {
            return this.isOn;
        }
    }
    
    public class Button {
    
        private Light light;
    
        public Button(Light light) {
            this.light = light;
        }
    
        public void press() {
            light.off(); 
            //버튼을 켜야한다면 이부분을 변경해야한다. 
        }
    
        public static void main(String[] args) {
            Button button = new Button(new Light());
            button.press();
            button.press();
            button.press();
            button.press();
        }
    }
    
    
    
    public class Game {
    
        private boolean isStarted;
    
        public void start() {
            System.out.println("게임을 시작합니다.");
            this.isStarted = true;
        }
    
        public void end() {
            System.out.println("게임을 종료합니다.");
            this.isStarted = false;
        }
    
        public boolean isStarted() {
            return isStarted;
        }
    }
    
    
    public class MyApp {
    
        private Game game;
    
        public MyApp(Game game) {
            this.game = game;
        }
    
        public void press() {
            game.start();
        }
    
        public static void main(String[] args) {
            Button button = new Button(new Light());
            button.press();
            button.press();
            button.press();
            button.press();
        }
    }
    
    ライトを消したり、ゲームクラスを書いたり、ゲームコードを変更するたびにコードを変更します.
    ライト、ゲームはReceiver
    ボタン、MyAppのコードはInvokerに相当します.
    コマンドモードの適用
    public interface Command {
    
        void execute();
    }
    
    public class GameStartCommand implements Command{
    
        private Game game;
    
        public GameStartCommand(Game game) {
            this.game = game;
        }
    
        @Override
        public void execute() {
            game.start();
        }
        
    }
    
    public class GameEndCommand implements Command{
    
        private Game game;
    
        public GameEndCommand(Game game) {
            this.game = game;
        }
    
        @Override
        public void execute() {
            game.end();
        }
    }
    
    public class LightOnCommand implements Command{
    
        private Light light;
    
        public LightOnCommand(Light light) {
            this.light = light;
        }
    
        @Override
        public void execute() {
            light.on();
        }
        
    }
    
    public class LightOffCommand implements Command{
    
        private Light light;
    
        public LightOffCommand(Light light) {
            this.light = light;
        }
    
        @Override
        public void execute() {
            light.off();
        }
    
    }
    public class Button {
    
        private Command command;
    
        public Button(Command command) {
            this.command = command;
        }
    
        public void press() {
            command.execute();
    
        }
    
        public static void main(String[] args) {
            Button button = new Button(new LightOnCommand(new Light())); //불을키고싶다. 
            //게임을 시작하고싶다면 
            //new GameStartCommand(new Game()))); 
            
            
            button.press();
            button.press();
        }
    }
    
    呼び出し元のコードは変更されません.
    command側のコードを変更するだけでいいです.
    ボタン側のコードは変更され、コマンド側のコードは
    朝三暮四じゃないの?
    特定の条件の下で、コマンドは変更するしかありません.
    重要なのは、呼び出し元のコードが変更されないことです.
    変化する部分を最小化すればいい.

    長所
  • は、既存のコードを変更することなく、新しいコードを作成することができる.
  • 受信者のコードが変更されても、発信者のコードは変更されません.
  • また、
  • コマンドオブジェクトを記録、データベース記憶、およびネットワーク転送するなど、さまざまな方法を用いることもできる.
  • 短所
  • コードは複雑で、クラスが増えています.
  • 割り込みモード


    語源は翻訳者であっても演奏者であってもよい.
    public class PostfixNotation {
    
        private final String expression;
    
        public PostfixNotation(String expression) {
            this.expression = expression;
        }
    
        public static void main(String[] args) {
            PostfixNotation postfixNotation = new PostfixNotation("123+-");
            postfixNotation.calculate();
        }
    
        private void calculate() {
            Stack<Integer> numbers = new Stack<>();
    
            for (char c : this.expression.toCharArray()) {
                switch (c) {
                    case '+':
                        numbers.push(numbers.pop() + numbers.pop());
                        break;
                    case '-':
                        int right = numbers.pop();
                        int left = numbers.pop();
                        numbers.push(left - right);
                        break;
                    default:
                        numbers.push(Integer.parseInt(c + ""));
                }
            }
    
            System.out.println(numbers.pop());
        }
    }
    
    接尾辞を計算するコード
    接尾辞タグ式を頻繁に使用する場合は、123+-の数値だけを変更し、他の数値を追加する必要があります.
    彼らに計算させる方法が必要かもしれません.

    Context=公開情報が含まれている場所.グローバル価値の集積地
    Expression=これらの値を参照
    TerminalExpression=x,y,z値
    
    public interface PostfixExpression {
        int interpret(Map<Character, Integer> context);
    }
    
    
    
    public class PlusExpression implements PostfixExpression{
    
        private PostfixExpression left, right;
    
        public PlusExpression(PostfixExpression left, PostfixExpression right) {
            this.left = left;
            this.right = right;
        }
    
        @Override
        public int interpret(Map<Character, Integer> context) {
    
            return left.interpret(context) + right.interpret(context);
        }
    }
    
    
    
    
    public class MinusExpression implements PostfixExpression{
    
        private PostfixExpression left, right;
    
    
        public MinusExpression(PostfixExpression left, PostfixExpression right) {
            this.left = left;
            this.right = right;
        }
    
        @Override
        public int interpret(Map<Character, Integer> context) {
    
            return left.interpret(context) - right.interpret(context);
        }
    }
    
    
    
    
    
    public class PostfixParser {
    
        public static PostfixExpression parse(String expression) {
            Stack<PostfixExpression> stack = new Stack<>();
            for (char c : expression.toCharArray()) {
                stack.push(getExpression(c, stack));
            }
            return stack.pop();
        }
    
        private static PostfixExpression getExpression(char c, Stack<PostfixExpression> stack) {
            switch (c) {
                case '+':
                    return new PlusExpression(stack.pop(), stack.pop());
                case '-':
                    PostfixExpression right = stack.pop();
                    PostfixExpression left = stack.pop();
                    return new MinusExpression(left, right);
                default:
                    return new VariableExpression(c);
            }
    
        }
    
    
    }
    
    
    
    
    
    
    public class VariableExpression implements PostfixExpression{
    
        private Character variable;
    
        public VariableExpression(Character variable) {
            this.variable = variable;
        }
    
        @Override
        public int interpret(Map<Character, Integer> context) {
            return context.get(variable);
        }
    }
    
    
    
    
    
    
    public class App {
        public static void main(String[] args) {
            PostfixExpression expression = PostfixParser.parse("xyz+-");
            int result = expression.interpret(Map.of('x', 1, 'y', 2, 'z', 3));
            System.out.println(result);
        }
    }
    

    エンタープライズ・モデルの利点
    既存のコードを変更せずにExpressionを追加できます.短所
  • 複雑度
  • 増加
    実施費用と頻繁に使用されるモデルかどうかを考慮すべきである.