๋””์ž์ธ ํŒจํ„ด/GOF

๐Ÿ’  Chain Of Responsibility ํŒจํ„ด - ์™„๋ฒฝ ๋งˆ์Šคํ„ฐํ•˜๊ธฐ

์ธํŒŒ_ 2023. 3. 22. 08:57

Chain-Of-Responsibility
Chain-Of-Responsibility

Chain Of Responsibility Pattern

์ฑ…์ž„ ์—ฐ์‡„ ํŒจํ„ด(Chain Of Responsibility Pattern, COR)์€ ํด๋ผ์ด์–ดํŠธ์˜ ์š”์ฒญ์— ๋Œ€ํ•œ ์„ธ์„ธํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๊ฐ€ ๋ชฝ๋•… ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ฒ˜๋ฆฌ ๊ฐ์ฒด๋“ค๋กœ ๋‚˜๋ˆ„๊ณ , ์ด๋“ค์„ ์‚ฌ์Šฌ(chain) ์ฒ˜๋Ÿผ ์—ฐ๊ฒฐํ•ด ์ง‘ํ•ฉ ์•ˆ์—์„œ ์—ฐ์‡„์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ํ–‰๋™ ํŒจํ„ด์ด๋‹ค.

์ด๋Ÿฌํ•œ ์ฒ˜๋ฆฌ ๊ฐ์ฒด๋“ค์„ ํ•ธ๋“ค๋Ÿฌ(handler)๋ผ๊ณ  ๋ถ€๋ฅด๋Š”๋ฐ, ์š”์ฒญ์„ ๋ฐ›์œผ๋ฉด ๊ฐ ํ•ธ๋“ค๋Ÿฌ๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€, ์—†์œผ๋ฉด ์ฒด์ธ์˜ ๋‹ค์Œ ํ•ธ๋“ค๋Ÿฌ๋กœ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ์ฑ…์ž„์„ ์ „๊ฐ€ํ•œ๋‹ค. ํ•œ๋งˆ๋””๋กœ ์ฑ…์ž„ ์—ฐ์‡„๋ผ๋Š” ๋ง์€ ์š”์ฒญ์— ๋Œ€ํ•œ ์ฑ…์ž„์„ ๋‹ค๋ฅธ ๊ฐ์ฒด์— ๋– ๋„˜๊ธด๋‹ค๋Š” ์†Œ๋ฆฌ์ด๋‹ค. ๋– ๋„˜๊ธด๋‹ค๊ณ  ํ•˜๋‹ˆ๊นŒ ๋ถ€์ •์ ์ธ ์˜๋ฏธ๋กœ ๋“ค๋ฆด์ˆ˜๋„ ์žˆ๊ฒ ์ง€๋งŒ, ์ด๋Ÿฌํ•œ ์ฒด์ธ ๊ตฌ์„ฑ์€ ํ•˜๋‚˜์˜ ๊ฐ์ฒด์— ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ์ฑ…์ž„์„ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ์ชฝ(sender)๊ณผ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š”(receiver) ์ชฝ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐ ๊ฐ์ฒด๋ฅผ ๋ถ€ํ’ˆ์œผ๋กœ ๋…๋ฆฝ์‹œํ‚ค๊ณ  ๊ฒฐํ•ฉ๋„๋ฅผ ๋Š์Šจํ•˜๊ฒŒ ๋งŒ๋“ค๋ฉฐ, ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ๊ฐ์ฒด๊ฐ€ ๋ณ€ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์—๋„ ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ํŠนํžˆ๋‚˜ ์ค‘์ฒฉ if-else๋ฌธ๋“ค์„ ์ตœ์ ํ™”ํ•˜๋Š”๋ฐ ์žˆ์–ด ์‹ค๋ฌด์—์„œ๋„ ๋งŽ์ด ์• ์šฉ๋˜๋Š” ํŒจํ„ด์ค‘ ํ•˜๋‚˜์ด๊ธฐ๋„ ํ•˜๋‹ค.

 

์ข€ ๋” ์ ‘๊ทผํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์‹ค์ƒํ™œ๋กœ ๋น„์œ ๋ฅผ ๋“ ๋‹ค๋ฉด, ์˜ˆ๋ฅผ๋“ค์–ด ์†Œ๋น„์ž๊ฐ€ ๋ฌธ์˜๋ฅผ ์œ„ํ•ด ๊ณ ๊ฐ์„ผํ„ฐ์— ์ „ํ™”๋ฅผ ๊ฑธ์—ˆ๋‹ค๊ณ  ํ•ด๋ณด์ž. ๊ทธ๋Ÿฌ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์ˆœ์„œ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ด๋ณธ ๊ฒฝํ—˜์„ ํ•œ ๋ฒˆ ์”ฉ์€ ๊ฒช์–ด ๋ดค์„ ๊ฒƒ์ด๋‹ค.

  1. ์ฒซ ๋ฒˆ์งธ๋กœ, ์ž๋™ ์‘๋‹ต๊ธฐ ์Œ์„ฑ ๋กœ๋ด‡์ด ์‘๋‹ตํ•˜๊ฒŒ ๋œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋งŒ์ผ ์Œ์„ฑ ๋กœ๋ด‡์ด ์ œ์‹œํ•˜๋Š” ํ•ด๊ฒฐ์ฑ…์— ๋Œ€ํ•ด์„œ 1๋ถ€ํ„ฐ 4๊นŒ์ง€ ์„ ํƒ์‚ฌํ•ญ์ค‘ ํ•ด๋‹นํ•˜๋Š” ๋ฒˆํ˜ธ๊ฐ€ ์—†๋‹ค๋ฉด ์•„๋งˆ ์—ฌ๋Ÿฌ๋ถ„๋„ ๊ทธ๋ ‡๊ณ  ๋Œ€๋‹ค์ˆ˜์˜ ์‚ฌ๋žŒ๋“ค์ด ๊ธฐํƒ€ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์ƒ๋‹ด์› ์—ฐ๊ฒฐ์„ ๋ˆ„๋ฅผ ๊ฒƒ์ด๋‹ค.
  2. ๋‘ ๋ฒˆ์งธ๋กœ, ์ƒ๋‹ด์‚ฌ๊ฐ€ ์ „ํ™”๋ฅผ ๋ฐ›์•˜์ง€๋งŒ ๊ธธ๊ฒŒ ํ†ตํ™”ํ•œ ๊ฒฐ๊ณผ ์ œ๋Œ€๋กœ๋œ ๊ธฐ์ˆ ์ ์ธ ๋„์›€์„ ๋ฐ›์ง€ ๋ชปํ–ˆ๋‹ค๊ณ  ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ƒ๋‹ด์›์ด ์ง์ ‘ ์—”์ง€๋‹ˆ์–ด์—๊ฒŒ ์ „ํ™”๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๊ฒŒ ๋œ๋‹ค.
  3. ์„ธ ๋ฒˆ์งธ๋กœ, ์—”์ง€๋‹ˆ์–ด์™€ ํ†ตํ™”ํ•˜๊ณ  ์ ํ•ฉํ•œ ์†”๋ฃจ์…˜์„ ์ œ์‹œํ•ด์คŒ์œผ๋กœ์จ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์–ด ํ†ตํ™”๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค.

Chain-Of-Responsibility
์ž๋™ ์‘๋‹ต๊ธฐ -> ์ƒ๋‹ด์‚ฌ -> ์—”์ง€๋‹ˆ์–ด ์ฒด์ธ ๊ตฌ์„ฑ

๋งˆ์น˜ ์†Œ๋น„์ž์˜ ์š”์ฒญ์— ๋Œ€ํ•ด ๊ฐ ์ฒ˜๋ฆฌ ์„œ๋น„์Šค๋“ค์ด ๋ฌด์—‡์ธ๊ฐ€ ์ฒด์ธ์ฒ˜๋Ÿผ ์—ฐ๊ฒฐ๋˜๋Š” ํ๋ฆ„์ด ๋˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ ๋ณด์ผ ๊ฒƒ์ด๋‹ค.

์—ฌ๊ธฐ์„œ ํ•ธ๋“ค๋Ÿฌ(Handler)๋Š” ์ž๋™ ์‘๋‹ต๊ธฐ ๋กœ๋ด‡, ์ƒ๋‹ด์‚ฌ, ์—”์ง€๋‹ˆ์–ด๊ฐ€ ๋œ๋‹ค. ์ฆ‰, ๊ฐ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€์˜ ์—ฌ๋ถ€๋ฅผ ๋”ฐ์ง€๊ณ  ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ๋‹ค์Œ ํ•ธ๋“ค๋Ÿฌ๋กœ  ๋– ๋„˜๊ธฐ๋Š” ๊ณผ์ •์„ ์ง„ํ–‰ํ•œ ๊ฒƒ์„ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด ์ฑ…์ž„ ์—ฐ์‡„ ํŒจํ„ด์ธ ๊ฒƒ์ด๋‹ค.


์ฑ…์ž„ ์—ฐ์‡„ ํŒจํ„ด ๊ตฌ์กฐ

Chain-Of-Responsibility

  • Handler : ์š”์ฒญ์„ ์ˆ˜์‹ ํ•˜๊ณ  ์ฒ˜๋ฆฌ ๊ฐ์ฒด๋“ค์˜ ์ง‘ํ•ฉ์„ ์ •์˜ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค
  • ConcreteHandler : ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์‹ค์ œ ์ฒ˜๋ฆฌ ๊ฐ์ฒด
    • ํ•ธ๋“ค๋Ÿฌ์— ๋Œ€ํ•œ ํ•„๋“œ๋ฅผ ๋‚ด๋ถ€์— ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋‹ค์Œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฒด์ธ์‹œํ‚ค๊ณ  ๋‹ค์Œ  ๋ฐ”๋ผ๋ณธ๋‹ค. 
    • ์ž์‹ ์ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋Š” ์š”๊ตฌ๊ฐ€ ๋‚˜์˜ค๋ฉด ๋ฐ”๋ผ๋ณด๊ณ  ์žˆ๋Š” ๋‹ค์Œ ์ฒด์ธ์˜ ํ•ธ๋“ค๋Ÿฌ์—๊ฒŒ ์š”์ฒญ์„ ๋– ๋„˜๊ธด๋‹ค.
    • ConcreteHandler1 - ConcreteHandler2 - ConcreteHandler3 - ... ์ด๋Ÿฐ์‹์œผ๋กœ ์ฒด์ธ ํ˜•์‹์ด ๊ตฌ์„ฑ๋˜๊ฒŒ ๋œ๋‹ค.
  • Client : ์š”์ฒญ์„ Handler ์ „๋‹ฌํ•œ๋‹ค

์—ฌ๊ธฐ์„œ ํ•ธ๋“ค๋Ÿฌ๋ผ๋ฆฌ ์ฒด์ด๋‹ ๋˜๋Š” ๊ตฌ์กฐ๋Š” ์–ด๋–ค ํ˜•ํƒœ์ด๋“  ์ƒ๊ด€์ด ์—†๋‹ค. ๋ฆฌ์ŠคํŠธํ˜• ์ผ์ˆ˜๋„ ์žˆ๊ณ  ์„ ํ˜• ์ผ ์ˆ˜๋„ ์žˆ๊ณ  ํŠธ๋ฆฌ ํ˜•ํƒœ์ผ ์ˆ˜๋„ ์žˆ๋‹ค.


์ฑ…์ž„ ์—ฐ์‡„ ํŒจํ„ด ํŠน์ง•

 

ํŒจํ„ด ์‚ฌ์šฉ ์‹œ๊ธฐ

  • ํŠน์ • ์š”์ฒญ์„ 2๊ฐœ ์ด์ƒ์˜ ์—ฌ๋Ÿฌ ๊ฐ์ฒด์—์„œ ํŒ๋ณ„ํ•˜๊ณ  ์ฒ˜๋ฆฌํ•ด์•ผ ํ• ๋•Œ
  • ํŠน์ • ์ˆœ์„œ๋กœ ์—ฌ๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
  • ํ”„๋กœ๊ทธ๋žจ์ด ๋‹ค์–‘ํ•œ ๋ฐฉ์‹๊ณผ ์ข…๋ฅ˜์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜์ง€๋งŒ ์ •ํ™•ํ•œ ์š”์ฒญ ์œ ํ˜•๊ณผ ์ˆœ์„œ๋ฅผ ๋ฏธ๋ฆฌ ์•Œ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ
  • ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด ์ง‘ํ•ฉ์ด ๋™์ ์œผ๋กœ ์ •์˜๋˜์–ด์•ผ ํ•  ๋•Œ (์ฒด์ธ ์—ฐ๊ฒฐ์„ ๋Ÿฐํƒ€์ž„์—์„œ ๋™์ ์œผ๋กœ ์„ค์ •)

 

ํŒจํ„ด ์žฅ์ 

  • ํด๋ผ์ด์–ธํŠธ๋Š” ์ฒ˜๋ฆฌ ๊ฐ์ฒด์˜ ์ฒด์ธ ์ง‘ํ•ฉ ๋‚ด๋ถ€์˜ ๊ตฌ์กฐ๋ฅผ ์•Œ ํ•„์š”๊ฐ€ ์—†๋‹ค.
  • ๊ฐ๊ฐ์˜ ์ฒด์ธ์€ ์ž์‹ ์ด ํ•ด์•ผํ•˜๋Š” ์ผ๋งŒ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒˆ๋กœ์šด ์š”์ฒญ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ์ฒด ์ƒ์„ฑ์ด ํŽธ๋ฆฌํ•ด์ง„๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฒด์ธ์— ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌ ์ˆœ์„œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ์–ด ์œ ์—ฐํ•ด์ง„๋‹ค
  • ์š”์ฒญ์˜ ํ˜ธ์ถœ์ž(invoker)์™€ ์ˆ˜์‹ ์ž(receiver)  ๋ถ„๋ฆฌ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. 
    • ์š”์ฒญ์„ ํ•˜๋Š” ์ชฝ๊ณผ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ชฝ์„ ๋””์ปคํ”Œ๋ง ์‹œ์ผœ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ˜๋‹ค
    • ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋ฐ”๋€Œ๋”๋ผ๋„ ํ˜ธ์ถœ์ž ์ฝ”๋“œ๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.

 

ํŒจํ„ด ๋‹จ์ 

  • ์‹คํ–‰ ์‹œ์— ์ฝ”๋“œ์˜ ํ๋ฆ„์ด ๋งŽ์•„์ ธ์„œ ๊ณผ์ •์„ ์‚ดํŽด๋ณด๊ฑฐ๋‚˜ ๋””๋ฒ„๊น… ๋ฐ ํ…Œ์ŠคํŠธ๊ฐ€ ์‰ฝ์ง€ ์•Š๋‹ค.
  • ์ถฉ๋ถ„ํ•œ ๋””๋ฒ„๊น…์„ ๊ฑฐ์น˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ์ง‘ํ•ฉ ๋‚ด๋ถ€์—์„œ ๋ฌดํ•œ ์‚ฌ์ดํด์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์š”์ฒญ์ด ๋ฐ˜๋“œ์‹œ ์ˆ˜ํ–‰๋œ๋‹ค๋Š” ๋ณด์žฅ์ด ์—†๋‹ค. (์ฒด์ธ ๋๊นŒ์ง€ ๊ฐ”๋Š”๋ฐ๋„ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค)
  • ์ฑ…์ž„ ์—ฐ์‡„๋กœ ์ธํ•œ ์ฒ˜๋ฆฌ ์ง€์—ฐ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋งŒ ์ด๋Š” ํŠธ๋ ˆ์ด๋“œ ์˜คํ”„๋กœ์„œ ์š”์ฒญ๊ณผ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๊ด€๊ณ„๊ฐ€ ๊ณ ์ •์ ์ด๊ณ  ์†๋„๊ฐ€ ์ค‘์š”ํ•˜๋ฉด ์ฑ…์ž„ ์—ฐ์‡„ ํŒจํ„ด ์‚ฌ์šฉ์„ ์œ ์˜ํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์•Œ์•„๋ณด๋Š” Chain Of Responsibility ํŒจํ„ด

 

์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์—ฐ๊ฒฐ์ง–๊ธฐ

์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ url ๋ฌธ์ž์—ด์„ ์ž…๋ ฅ๋ฐ›์œผ๋ฉด, ๊ฐ url์˜ ํ”„๋กœํ† ์ฝœ, ๋„๋ฉ”์ธ, ํฌํŠธ๋ฅผ ํŒŒ์‹ฑํ•ด์„œ ์ •๋ณด๋ฅผ ์ถœ๋ ฅํ•ด์ฃผ๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ ๋‹ค๊ณ  ํ•ด๋ณด์ž.

 

ํด๋ฆฐํ•˜์ง€ ์•Š์€ ๋ฌธ์ œ์˜ ์ฝ”๋“œ โŒ

์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ฒ˜๋ฆฌ๋ฌธ์„ ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ๋กœ ํ†ต์งœ๋กœ ๊ตฌ์„ฑํ•  ๊ฒƒ์ด๋‹ค.

class UrlParser {
    public static void run(String url) {
        // protocol ํŒŒ์‹ฑ
        int index = url.indexOf("://");
        if (index != -1) {
            System.out.println("PROTOCOL : " + url.substring(0, index));
        } else {
            System.out.println("NO PROTOCOL");
        }

        // domain ํŒŒ์‹ฑ
        int startIndex = url.indexOf("://");
        int lastIndex = url.lastIndexOf(":");

        System.out.print("DOMAIN : ");
        if (startIndex == -1) {
            if (lastIndex == -1) {
                System.out.println(url);
            } else {
                System.out.println(url.substring(0, lastIndex));
            }
        } else if (startIndex != lastIndex) {
            System.out.println(url.substring(startIndex + 3, lastIndex));
        } else {
            System.out.println(url.substring(startIndex + 3));
        }

        // port ํŒŒ์‹ฑ
        int index2 = url.lastIndexOf(":");
        if (index2 != -1) {
            String strPort = url.substring(index2 + 1);
            try {
                int port = Integer.parseInt((strPort));
                System.out.println("PORT : " + port);
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }

    }
}
class Client {
    public static void main(String[] args) {
        String url1 = "http://www.youtube.com:80";
        System.out.println("INPUT: " + url1);
        UrlParser.run(url1);

        String url2 = "https://www.inpa.tistory.com:443";
        System.out.println("INPUT: " + url2);
        UrlParser.run(url2);

        String url3 = "http://localhost:8080";
        System.out.println("INPUT: " + url3);
        UrlParser.run(url3);
    }
}

Chain-Of-Responsibility

๋™์ž‘์—๋Š” ๋ฌธ์ œ๋Š” ์—†์ง€๋งŒ, ์ด๋Ÿฐ์‹์œผ๋กœ ๊ตฌ์„ฑํ•  ๊ฒฝ์šฐ ๋งŒ์ผ path๋‚˜ queryString๋„ ๊ตฌํ•˜๋Š” ์ƒˆ๋กœ์šด ์ฒ˜๋ฆฌ ๋กœ์ง์ด ์ถ”๊ฐ€๋  ๊ฒฝ์šฐ ๋ฉ”์„œ๋“œ ๋กœ์ง์„ ํ†ต์งœ๋กœ ์ˆ˜์ •ํ•ด์•ผํ•  ๊ฒƒ์ด๊ณ  ์ด์ „์˜ ๋กœ์ง๊ณผ ๊ฒน์น˜๋Š”๊ฒŒ ์—†๋Š”์ง€ ๋ณต๊ธฐํ•ด์•ผ ํ•œ๋‹ค. ๋‹น์žฅ ์ฝ”๋“œ๋งŒ ๋ด๋„ ํ”„๋กœํ† ์ฝœ, ๋„๋ฉ”์ธ, ํฌํŠธ๋ฅผ ๊ตฌํ•˜๋Š”๋ฐ ์žˆ์–ด indexOf() ๋ฉ”์„œ๋“œ๋ฅผ ์ž์ฒด์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด ๊ฒน์น˜๋Š” ๋ถ€๋ถ„์ด ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ํฌํŠธ ์ •๋ณด๋Š” ์›ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ์ฝ”๋“œ๋ฅผ ์ง€์šธ์ˆ˜๋Š” ์—†์œผ๋‹ˆ ํฌํŠธ ํŒŒ์‹ฑ ๋ถ€๋ถ„๋งŒ ๋บ€ ๋น„์Šทํ•œ ์ฝ”๋“œ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฉ”์„œ๋“œ๋ฅผ ๋”ฐ๋กœ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค. ์ด๋Š” ์š”๊ตฌ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์ค‘์•™ ์ง‘๊ถŒ์ ์œผ๋กœ ๋ชจ๋‘ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•˜๋Š” ํ˜„์ƒ์ด๋‹ค.

 

์ฑ…์ž„ ์—ฐ์‡„ ํŒจํ„ด์„ ์ ์šฉํ•œ ์ฝ”๋“œ โœ”๏ธ

๊ทธ๋ ‡๋‹ค๋ฉด ํ”„๋กœํ† ์ฝœ๋งŒ์„ ํŒŒ์‹ฑํ•˜๋Š” ์ฑ…์ž„๊ณผ ๋„๋ฉ”์ธ๋งŒ์„ ํŒŒ์‹ฑํ•˜๋Š” ์ฑ…์ž„ ์ด๋ ‡๊ฒŒ ์ฒ˜๋ฆฌ ์ฑ…์ž„์„ ๊ฐ ๊ฐ์ฒด๋“ค๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ์ด๋“ค ๋ผ๋ฆฌ ์ฒด์ธ์œผ๋กœ ์—ฐ๊ฒฐํ•จ์œผ๋กœ์จ ์ข€๋” ์œ ์—ฐํ•˜๊ฒŒ ํ”„๋กœ๊ทธ๋žจ ๋กœ์ง์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ์ด๋ฅผ ๊ทธ๋ฆผ์œผ๋กœ ํ‘œํ˜„ํ•˜์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

Chain-Of-Responsibility

ํ•ธ๋“ค๋Ÿฌ๋Š” ๋ณธ์ธ์˜ ์—ญํ• ๋งŒ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์ถ”๊ฐ€ ์ฒ˜๋ฆฌ ๋กœ์ง์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ์œ ์—ฐํ•˜๊ฒŒ ์ฒด์ธ์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋˜๋ฉฐ ์ฒด์ธ์„ ๊ตฌ์กฐ์ ์œผ๋กœ ๋‹ค์–‘ํ•˜๊ฒŒ ๊ตฌ์„ฑํ• ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

์ฑ…์ž„ ์—ฐ์‡„๋ฅผ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š๋‹ค. ๊ธฐ์กด์˜ ์ฝ”๋“œ์—์„œ ๊ฐ ๋‹ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์„ ๋”ฐ๋กœ ํ•ธ๋“ค๋Ÿฌ(Handler) ๊ฐ์ฒด๋กœ ๋‚ด๋นผ์ฃผ๋ฉด ๋œ๋‹ค.

Chain-Of-Responsibility

์ „๋žต ํŒจํ„ด์ด ์ „๋žต ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ฝ”๋“œ๋ฅผ ๊ฐ์ฒดํ™” ํ•œ ๊ฒƒ์ด๊ณ , ์ƒํƒœ ํŒจํ„ด์€ ๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ, ๋ช…๋ น ํŒจํ„ด์ด ์ปค๋งจ๋“œ๋ฅผ ๊ฐ์ฒดํ™” ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด, ์ฑ…์ž„ ์—ฐ์‡„ ํŒจํ„ด์€ ์กฐ๊ฑด๋ฌธ์˜ ์š”์ฒญ ์ฒ˜๋ฆฌ ๋กœ์ง ์ž์ฒด๋ฅผ ๊ฐ์ฒดํ™” ํ•œ ๊ฒƒ์œผ๋กœ ๋ณด๋ฉด ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ผ๋ฐ˜์ ์ธ ์กฐ๊ฑด ๋ถ„๊ธฐ๋ฌธ ๊ฐ™์€ ๊ฒฝ์šฐ ๋‹ค์ค‘์œผ๋กœ ๊ตฌ์„ฑ๋  ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ด๋ฅผ ์ฒด์ธ์œผ๋กœ ๊ฐ์ฒด๋ผ๋ฆฌ ์—ฐ๊ฒฐํ•จ์œผ๋กœ์จ, ๊ฐ if๋ฌธ ๋กœ์ง์„ ํด๋ž˜์Šค๋กœ ํ‘œํ˜„ํ•˜์˜€๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

Chain-Of-Responsibility

// ๊ตฌ์ฒด์ ์ธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ฌถ๋Š” ์ธํ„ฐํŽ˜์ด์Šค (์ถ”์ƒ ํด๋ž˜์Šค)
abstract class Handler {
    // ๋‹ค์Œ ์ฒด์ธ์œผ๋กœ ์—ฐ๊ฒฐ๋  ํ•ธ๋“ค๋Ÿฌ
    protected Handler nextHandler = null;

    // ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ์‹œํ‚ฌ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋ก
    public Handler setNext(Handler handler) {
        this.nextHandler = handler;
        return handler; // ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹ ๊ตฌ์„ฑ์„ ์œ„ํ•ด ์ธ์ž๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•จ
    }

    // ์ž์‹ ํ•ธ๋“ค๋Ÿฌ์—์„œ ๊ตฌ์ฒดํ™” ํ•˜๋Š” ์ถ”์ƒ ๋ฉ”์„œ๋“œ
    protected abstract void process(String url);

    // ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์š”์ฒญ์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ 
    public void run(String url) {
        process(url);

        // ๋งŒ์ผ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์—ฐ๊ฒฐ๋œ๊ฒŒ ์žˆ๋‹ค๋ฉด ๋‹ค์Œ ํ•ธ๋“ค๋Ÿฌ๋กœ ์ฑ…์ž„์„ ๋– ๋„˜๊ธด๋‹ค
        if (nextHandler != null)
            nextHandler.run(url);
    }
}
class ProtocolHandler extends Handler {
    @Override
    protected void process(String url) {
        int index = url.indexOf("://");
        if (index != -1) {
            System.out.println("PROTOCOL : " + url.substring(0, index));
        } else {
            System.out.println("NO PROTOCOL");
        }
    }
}

class DomianHandler extends Handler {
    @Override
    protected void process(String url) {
        int startIndex = url.indexOf("://");
        int lastIndex = url.lastIndexOf(":");

        System.out.print("DOMAIN : ");
        if (startIndex == -1) {
            if (lastIndex == -1) {
                System.out.println(url);
            } else {
                System.out.println(url.substring(0, lastIndex));
            }
        } else if (startIndex != lastIndex) {
            System.out.println(url.substring(startIndex + 3, lastIndex));
        } else {
            System.out.println(url.substring(startIndex + 3));
        }
    }
}

class PortHandler extends Handler {
    @Override
    protected void process(String url) {
        int index = url.lastIndexOf(":");
        if (index != -1) {
            String strPort = url.substring(index + 1);
            try {
                int port = Integer.parseInt((strPort));
                System.out.println("PORT : " + port);
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }
    }
}
class Client {
    public static void main(String[] args) {
        // 1. ํ•ธ๋“ค๋Ÿฌ ์ƒ์„ฑ
        Handler handler1 = new ProtocolHandler();
        Handler handler2 = new DomianHandler();
        Handler handler3 = new PortHandler();

        // 2. ํ•ธ๋“ค๋Ÿฌ ์—ฐ๊ฒฐ ์„ค์ • (handler1 → handler2 → handler3)
        handler1.setNext(handler2).setNext(handler3);

        // 3. ์š”์ฒญ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ ์—ฐ์‡„ ์‹คํ–‰
        String url1 = "http://www.youtube.com:80";
        System.out.println("INPUT: " + url1);
        handler1.run(url1);

        System.out.println();

        String url2 = "https://www.inpa.tistory.com:443";
        System.out.println("INPUT: " + url2);
        handler1.run(url2);

        System.out.println();

        String url3 = "http://localhost:8080";
        System.out.println("INPUT: " + url3);
        handler1.run(url3);
    }
}

Chain-Of-Responsibility


์ค‘์ฒฉ๋œ if-else ๋ฌธ ์žฌ๊ตฌ์„ฑํ•˜๊ธฐ

์ฒซ๋ฒˆ์งธ ํŒจํ„ด ์˜ˆ์ œ๋Š” ์ค‘์•™ ์ง‘๊ถŒํ™”ํ•œ ๋กœ์ง์„ ํ•ธ๋“ค๋Ÿฌ ๊ฐ์ฒด๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฑ…์ž„์„ ๋ถ„์‚ฐ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ–ˆ๋‹ค๋ฉด, ๋‘๋ฒˆ์งธ ํŒจํ„ด ์˜ˆ์ œ๋Š” ์ค‘์ฒฉ๋œ if-else ์กฐ๊ฑด๋ฌธ์„ ์ฑ…์ž„ ์—ฐ์‡„ ํŒจํ„ด์œผ๋กœ ์œ ์—ฐํ•˜๋ฉฐ ๊ฐ€๋…์„ฑ ์ข‹๊ฒŒ ๊ตฌ์„ฑํ•˜๋Š” ์‚ฌ๋ก€๋ฅผ ๋“ค์–ด๋ณผ ๊ฒƒ์ด๋‹ค.

 

ํด๋ฆฐํ•˜์ง€ ์•Š์€ ๋ฌธ์ œ์˜ ์ฝ”๋“œ โŒ

์„œ๋ฒ„๊ฐ€ ์žˆ๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์ธ ํ•˜๋Š” ๊ณผ์ •์„ ์ž๋ฐ”์˜ ํด๋ž˜์Šค๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ‘œํ˜„ํ•ด ๋ณด์•˜๋‹ค. ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด๋ณด์—ฌ ์–ด๋ ค์›Œ๋ณด์ด์ง€๋งŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌ์„ฑํ•ด๋ณธ ์˜ˆ์ œ์ด๋‹ค. ์„œ๋ฒ„๋Š” ๊ฐ์ข… ์‚ฌ์šฉ์ž ์ •๋ณด๋“ค์„ Map ์ž๋ฃŒํ˜•ํƒœ๋กœ ์ง€๋‹ˆ๊ณ  ์žˆ๊ณ , ๋ฏธ๋“ค์›จ์–ด๋Š” ๊ฐ์ข… ๋กœ๊ทธ์ธ ์ธ์ฆ ๋กœ์ง๋“ค์„ ๊ด€๋ฆฌํ•˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ฐ์ข… ๋ฏธ๋“ค์›จ์–ด์˜ boolean ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์กฐ๊ฑด ๋ถ„๊ธฐ๋ฌธ์„ ํ†ตํ•ด ๋กœ๊ทธ์ธ ๊ณผ์ •์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

class Server {
    private Map<String, String> users = new HashMap<>();

    // ์„œ๋ฒ„์— ์œ ์ € ๋“ฑ๋ก
    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);
    }
}
class Middleware {
    private int limit = 3;
    private int count = 0;

    Server server;

    public Middleware(Server server) {
        this.server = server;
    }

    // ๋กœ๊ทธ์ธ ํšŸ์ˆ˜ ์‹œ๋„
    public boolean limitLoginAttempt() {
        if (count > limit) {
            System.out.println("๋กœ๊ทธ์ธ ์š”์ฒญ ํšŸ์ˆ˜ ์ œํ•œ !!");
            return false;
        }
        count++;
        return true;
    }

    // ์•„์ด๋””, ํŒจ์Šค์›Œ๋“œ ์ธ์ฆ
    public boolean authorize(String email, String password) {
        if (!server.hasEmail(email)) {
            System.out.println("๊ฐ€์ž…๋œ ์ด๋ฉ”์ผ ๊ณ„์ •์ด ์—†์Šต๋‹ˆ๋‹ค !");
            return false;
        }

        if (!server.isValidPassword(email, password)) {
            System.out.println("ํŒจ์Šค์›Œ๋“œ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค !");
            return false;
        }

        System.out.println("๋กœ๊ทธ์ธ ์™„๋ฃŒ !!");
        return true;
    }

    // ์‚ฌ์šฉ์ž๊ฐ€ admin ๊ณ„์ •์ธ์ง€, ํ˜น์€ ์ผ๋ฐ˜ user ๊ณ„์ •์ธ์ง€ ๊ฒ€์ฆ
    public boolean authentication(String email) {
        if (email.equals("inpa@tistory.com")) {
            System.out.println("Hello, admin!");
            return true;
        } else {
            System.out.println("Hello, user!");
            return false;
        }
    }

    // ๋งŒ์ผ ๊ด€๋ฆฌ์ž๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜ ์œ ์ €์ผ ๊ฒฝ์šฐ ์œ ์ €์˜ ์š”์ฒญ์— ๋Œ€ํ•ด์„  ๋ชจ๋‘ ๋กœ๊น…
    public void logging() {
        System.out.println("์š”์ฒญ์„ ๋กœ๊น…ํ•ฉ๋‹ˆ๋‹ค.");
    }
}
class Client {
    public static void main(String[] args) throws IOException {
        // 1. ์„œ๋ฒ„ ์ƒ์„ฑ ๋ฐ ๋“ฑ๋ก
        Server server = new Server();
        server.register("john@naver.com", "123123");
        server.register("kail@google.com", "456456");
        server.register("inpa@tistory.com", "789789");

        // 2. ์ธ์ฆ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฏธ๋“ค์›จ์–ด ์ƒ์„ฑ
        Middleware middleware = new Middleware(server);

        // 3. ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋กœ๊ทธ์ธ ์‹œ๋„
        do {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            System.out.print("\nEmail: ");
            String email = reader.readLine();
            System.out.print("Password: ");
            String password = reader.readLine();

            // ๋งŒ์ผ ๋กœ๊ทธ์ธ ํšŸ์ˆ˜๊ฐ€ ๋‚จ์•„์žˆ์„ ๊ฒฝ์šฐ
            if (middleware.limitLoginAttempt()) {
                // ์ด๋ฉ”์ผ ํŒจ์Šค์›Œ๋“œ ์ธ์ฆ
                if (middleware.authorize(email, password)) {
                    // ์ธ์ฆ๋˜์—ˆ์„ ๊ฒฝ์šฐ ์ผ๋ฐ˜ ์œ ์ € ๊ณ„์ •์ธ์ง€ ๊ด€๋ฆฌ์ž ๊ณ„์ •์ธ์ง€ ๊ฒ€์ฆ
                    if (middleware.authentication(email)) {
                        // ...
                    } else {
                        // ๊ด€๋ฆฌ์ž๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜ ์œ ์ € ๊ณ„์ •์ผ ๊ฒฝ์šฐ ๋กœ๊น… ์ฒ˜๋ฆฌ
                        middleware.logging();
                    }
                    break;
                } else {
                    continue;
                }
            } else {
                throw new RuntimeException("๋กœ๊ทธ์ธ ์‹œ๋„ ํšŸ์ˆ˜ ์ดˆ๊ณผ๋กœ ํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค");
            }
        } while (true);
    }
}

Chain-Of-Responsibility
Chain-Of-Responsibility

๋™์ž‘์€ ๋ฌธ์ œ์—†์–ด ๋ณด์ด์ง€๋งŒ ๋”ฑ๋ด๋„ ํด๋ผ์ด์–ธํŠธ ์ชฝ ์‹คํ–‰ ์ฝ”๋“œ๊ฐ€ ๊ต‰์žฅํžˆ ๋ณต์žกํ•˜๋‹ค. ์—ฌ๋Ÿฌ ์ธ์ฆ ๋กœ์ง๋“ค์„ ํ•˜๋‚˜ํ•˜๋‚˜ ๋”ฐ์ ธ๊ฐ€๋ฉฐ ๋งŒ์ผ '์ฐธ'์ผ ๊ฒฝ์šฐ ๋‹ค์Œ ์ธ์ฆ ๋กœ์ง์„ ๋”ฐ์ ธ๊ฐ€๋Š” ์ค‘์ฒฉ if-else๋ฌธ ํ˜•ํƒœ๋กœ ๋˜์–ด ์žˆ๋‹ค.

Chain-Of-Responsibility

์ด๋Ÿฐ ์ฝ”๋“œ๋Š” ์ฝ”๋“œ๋ฅผ ๋ณต๊ธฐํ• ๋•Œ๋‚˜ ํ…Œ์ŠคํŠธํ• ๋•Œ ๊ต‰์žฅํžˆ ๋‚œํ•ดํ•˜๊ฒŒ ๋˜๋ฉฐ ํŠนํžˆ๋‚˜ if๋ฌธ ์ค‘์ฒฉ์€ ๋‹จ๊ณ„๊ฐ€ ๋Š˜์–ด๋‚  ์ˆ˜๋ก ์ค‘์ฒฉ ๋ธ”๋ก์ด ๋ถ„๊ธฐ์—์„œ ์•ˆ์ •์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์‹ ํ•˜๊ธฐ๋„ ์–ด๋ ต๋‹ค. ๊ฑฐ๊ธฐ๋‹ค ๋งŒ์ผ ์ƒˆ๋กœ์šด ์ธ์ฆ ๋ฉ”์„œ๋“œ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค๋ฉด ๋ถ„๊ธฐ๋ฌธ ์ „์ฒด๋ฅผ ๋œฏ์–ด ๊ณ ์ณ์•ผ ๋  ์ˆ˜ ์žˆ๋‹ค.

Chain-Of-Responsibility
Chain-Of-Responsibility
์ฝ”๋“œ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ์ ์  ๋ณต์žกํ•ด์ง„๋‹ค

 

์ฑ…์ž„ ์—ฐ์‡„ ํŒจํ„ด์„ ์ ์šฉํ•œ ์ฝ”๋“œ โœ”๏ธ

๋ฌผ๋ก  ๊ฐ ์ธ์ฆ ๋กœ์ง๋“ค์ด ๋ณ„๊ฐœ์˜ ๋ฉ”์„œ๋“œ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์ง€๋งŒ, ๊ฒฐ๊ตญ ์‹คํ–‰๋ถ€์—์„  ๋ณต์žกํ•œ if-else๋กœ ๊ตฌ์„ฑ๋˜๋Š”๊ฑด ๋งˆ์ฐฌ๊ฐ€์ง€์ด๊ณ  ํ•˜๋‚˜์˜ ๋ฏธ๋“ค์›จ์–ด ํด๋ž˜์Šค์—์„œ ์ค‘์•™ ์ง‘๊ถŒ ์ ์ธ ์ฑ…์ž„์„ ์ง€๋‹ˆ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ฑ…์ž„ ์—ฐ์‡„ ํŒจํ„ด์œผ๋กœ ์ธ์ฆ ๋กœ์ง๋“ค์„ ๋ณ„๊ฐœ์˜ ํ•ธ๋“ค๋Ÿฌ ํด๋ž˜์Šค๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ์ฒด์ด๋‹ ํ•จ์œผ๋กœ์จ if-else ํ˜•ํƒœ๋ฅผ ๋ณด๋‹ค ์œ ์—ฐํ•˜๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜๊ฐ€ ์žˆ๊ฒŒ ๋œ๋‹ค.

Chain-Of-Responsibility
์ธ์ฆ ๋กœ์ง๋“ค์„ ๋ณ„๊ฐœ์˜ ํ•ธ๋“ค๋Ÿฌ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ์—ฐ๊ฒฐํ•œ๋‹ค

์ด๋ฒˆ ํŒจํ„ด ์ ์šฉ ์˜ˆ์ œ๋Š” ์ฒซ๋ฒˆ์งธ ์˜ˆ์ œ์™€๋Š” ์•ฝ๊ฐ„ ์ฐจ์ด๋ฅผ ๋‘์—ˆ๋Š”๋ฐ, ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋กœ ๊ฐ ๊ฐ์ฒด๋ณ„๋กœ ๊ตฌ์ฒดํ™” ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ๋ถ€๋ชจ์˜ check() ๋ฉ”์„œ๋“œ๋ฅผ ์ž์‹ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์˜ค๋ฒ„๋ผ์ด๋“œ(Override)ํ•˜๊ณ , ๋งŒ์ผ ์ฒด์ธ ํ˜ธ์ถœ์ด ํ•„์š”ํ•  ๊ฒฝ์šฐ super ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ๋ถ€๋ชจ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•จ์œผ๋กœ์จ ๋‹ค์Œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•˜๋Š”, ์ž๋ฐ” ํด๋ž˜์Šค์˜ ์ƒ์† ํŠน์ง•์„ ์ด์šฉํ•˜์˜€๋‹ค๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ ์š”์ฒญ์— ๋Œ€ํ•œ ๋กœ์ง ๋ฐ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ๋‘ ํ•ธ๋“ค๋Ÿฌ ํด๋ž˜์Šค์—๊ฒŒ ์œ„์ž„ ํ–ˆ์œผ๋‹ˆ, ๋ณต์žกํ•œ if-else ๋ถ„๊ธฐ์— ๋”ฐ๋ฅธ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ํ•ธ๋“ค๋Ÿฌ์—์„œ flag ๋ผ๋Š” ์ •์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•˜์—ฌ, ์‹คํ–‰๋ถ€์—์„œ ์ •์ˆ˜๊ฐ’์— ๋”ฐ๋ผ ๋ฃจํ”„๋ฌธ ๋™์ž‘์„ ์ œ์–ดํ•˜๋Š” ์‹์œผ๋กœ ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

Chain-Of-Responsibility

// Handler ์—ญํ• 
abstract class Middleware {
    // ๋‹ค์Œ ์ฒด์ธ์œผ๋กœ ์—ฐ๊ฒฐ๋  ํ•ธ๋“ค๋Ÿฌ
    protected Middleware nextMiddleware = null;

    // setter ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ์‹œํ‚ฌ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋ก
    public Middleware setNext(Middleware middleware) {
        this.nextMiddleware = middleware;
        return middleware; // ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹ ๊ตฌ์„ฑ์„ ์œ„ํ•ด ์ธ์ž๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•จ
    }

    // ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์š”์ฒญ์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ
    public short check(String email, String password) {
        /*
          flag๋Š” ํด๋ผ์ด์–ธํŠธ ์‹คํ–‰๋ถ€์—์„œ while๋ฌธ์„ ๋น ์ ธ๋‚˜๊ฐ€๊ธฐ ์œ„ํ•œ ์กฐ๊ฑด๊ฐ’์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค
          -2 : Exception ์ผ์œผํ‚ด
          -1 : break ๋™์ž‘ (๋ฃจํ”„๋ฌธ ์ข…๋ฃŒ)
          0 : continue ๋™์ž‘ (์ฒ˜์Œ๋ถ€ํ„ฐ ์ฝ˜์†” ์ž…๋ ฅ ๋ฐ›๊ธฐ)
          1 : ๊ทธ๋Œ€๋กœ ์ฒ˜๋ฆฌ๋ฅผ ์ง„ํ–‰ํ•จ
         */
        short flag = 1;

        // ๋งŒ์ผ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์—ฐ๊ฒฐ๋œ๊ฒŒ ์žˆ๋‹ค๋ฉด ๋‹ค์Œ ํ•ธ๋“ค๋Ÿฌ๋กœ ์ฑ…์ž„์„ ๋– ๋„˜๊ธด๋‹ค
        if (nextMiddleware != null) {
            flag = nextMiddleware.check(email, password);
        }

        return flag;
    }
}
// ConcreteHandler ์—ญํ• 
class LimitLoginAttemptMiddleware extends Middleware {
    private int limit = 3; // ๋กœ๊ทธ์ธ ์‹œ๋„ ์ตœ๋Œ€ ํšŸ์ˆ˜ 3ํšŒ
    private int count = 0;

    @Override
    public short check(String email, String password) {
        short flag = 1;

        if (count > limit) {
            System.out.println("๋กœ๊ทธ์ธ ์š”์ฒญ ํšŸ์ˆ˜ ์ œํ•œ !!");
            flag = -2; // Exception ํ”Œ๋ž˜๊ทธ
        } else {
            flag = super.check(email, password);
        }

        count++;

        return flag;
    }
}

class AuthorizeMiddleware extends Middleware {
    private Server server;

    public AuthorizeMiddleware(Server server) {
        this.server = server;
    }

    @Override
    public short check(String email, String password) {
        short flag = 1;

        if (!server.hasEmail(email)) {
            System.out.println("This email is not registered!");
            flag = 0; // continue ํ”Œ๋ž˜๊ทธ
        } else if (!server.isValidPassword(email, password)) {
            System.out.println("Wrong password!");
            flag = 0; // continue ํ”Œ๋ž˜๊ทธ
        } else {
            flag = super.check(email, password);
        }

        return flag;
    }
}

class AuthenticationMiddleware extends Middleware {
    @Override
    public short check(String email, String password) {
        short flag = 1;

        if (email.equals("inpa@tistory.com")) {
            System.out.println("Hello, admin!");
            flag = -1; // break ํ”Œ๋ž˜๊ทธ
        } else {
            System.out.println("Hello, user!");
            flag = super.check(email, password);
        }

        return flag;
    }
}

class LoggingMiddleware extends Middleware {
    @Override
    public short check(String email, String password) {
        System.out.println("์š”์ฒญ์„ ๋กœ๊น…ํ•ฉ๋‹ˆ๋‹ค.");
        return -1; // break ํ”Œ๋ž˜๊ทธ
    }
}
class Client {
    public static void main(String[] args) throws IOException {
        // 1. ์„œ๋ฒ„ ์ƒ์„ฑ ๋ฐ ๋“ฑ๋ก
        Server server = new Server();
        server.register("john@naver.com", "123123");
        server.register("kail@google.com", "456456");
        server.register("inpa@tistory.com", "789789");

        // 2. ์ธ์ฆ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•ธ๋“ค๋Ÿฌ ์ƒ์„ฑ
        LimitLoginAttemptMiddleware middleware1 = new LimitLoginAttemptMiddleware();
        AuthorizeMiddleware middleware2 = new AuthorizeMiddleware(server);
        AuthenticationMiddleware middleware3 = new AuthenticationMiddleware();
        LoggingMiddleware middleware4 = new LoggingMiddleware();

        // 3. ํ•ธ๋“ค๋Ÿฌ ์ฒด์ธ
        middleware1
                .setNext(middleware2)
                .setNext(middleware3)
                .setNext(middleware4);

        // 4. ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋กœ๊ทธ์ธ ์‹œ๋„
        do {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            System.out.print("\nEmail: ");
            String email = reader.readLine();
            System.out.print("Password: ");
            String password = reader.readLine();

            // ํ•ธ๋“ค๋Ÿฌ๋ถ€ํ„ฐ ์ •์ˆ˜ flag๋ฅผ ๋ฐ›์•„, ์ •์ˆ˜๊ฐ’์— ๋”ฐ๋ผ ๋ฃจํ”„๋ฌธ ๋‹ค์Œ ๋™์ž‘์„ ์ฒ˜๋ฆฌ
            short result = middleware1.check(email, password);

            if (result == -2) {
                throw new RuntimeException("๋กœ๊ทธ์ธ ์‹œ๋„ ํšŸ์ˆ˜ ์ดˆ๊ณผ๋กœ ํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค");
            } else if (result == -1) {
                break;
            } else if (result == 0) {
                continue;
            }

        } while (true);
    }
}

Chain-Of-Responsibility
Chain-Of-Responsibility

์˜คํžˆ๋ ค ๊ธฐ์กด ์ฝ”๋“œ๋ณด๋‹ค ๋””์ž์ธ ํŒจํ„ด์„ ์ ์šฉํ•œ ์ฝ”๋“œ๊ฐ€ ์–‘๋„ ๋งŽ์•„์ง€๊ณ  ๋ณต์žก์„ฑ์ด ์ฆ๊ฐ€ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋Š๋‚„ ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ, ์‹คํ–‰๋ถ€๋ฅผ ์ข€๋” ํ•œ๋ˆˆ์— ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ์‹ฌํ”Œํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ–ˆ๋‹ค๋ผ๋Š” ์ ์—์„œ ์˜์˜๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.


์‹ค๋ฌด์—์„œ ์ฐพ์•„๋ณด๋Š” Chain Of Responsibility ํŒจํ„ด

 

Java

  • java.util.logging.Logger์˜ log()
  • javax.servlet.Filter์˜ doFilter()

์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญ์‹œ ์„œ๋ธ”๋ฆฟ์— ์ ‘๊ทผํ•˜๊ธฐ ์ „์— ๋‹ค์–‘ํ•œ ํ•„ํ„ฐ๋ฅผ ๊ฑฐ์น˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ์•„๋ž˜์™€ ๊ฐ™์€ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์žˆ๊ณ , "/hello"๋กœ ์š”์ฒญ์„ ๋ฐ›์œผ๋ฉด ํ•„ํ„ฐ๋ฅผ ํƒ€๋„๋กํ•œ๋‹ค.

@ServletComponentScan
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
}
@WebFilter(urlPatterns = "/hello") // ํŠน์ • url ์„œ๋ธ”๋ฆฟ์— ์ ‘๊ทผํ• ์‹œ ๋‹ค์Œ ํ•„ํ„ฐ๋ฅผ ์ ์šฉ
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("๊ฒŒ์ž„ ๋");
    }
}

Spring Framework

์Šคํ”„๋ง ํ”„๋กœ์ ํŠธ์— Spring Securiry ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด Security ํ•„ํ„ฐ์— ๋Œ€ํ•œ ์ฒด์ธ์„ ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    // ์ฒด์ธ ํ•„ํ„ฐ๋ฅผ ์„ค์ •ํ•˜๋Š” ์ฝ”๋“œ
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ์ ‘๊ทผ๊ถŒํ•œ์„ ์ธ์ฆ์—†์ด ํ—ˆ๊ฐ€
        http.authorizeRequests().anyRequest().permitAll().and().addFilter(new MyFilter());
    }
}

# ์ฐธ๊ณ ์ž๋ฃŒ

์ฝ”๋”ฉ์œผ๋กœ ํ•™์Šตํ•˜๋Š” GoF์˜ ๋””์ž์ธ ํŒจํ„ด - ๋ฐฑ๊ธฐ์„ 

https://refactoring.guru/design-patterns/chain-of-responsibility

GIS DEVELOPER ์œ ํŠœ๋ธŒ - Chain of Responsibility