Skip to content

Commit 46fe034

Browse files
committed
커맨트 패턴 활용법
1 parent 45cbc50 commit 46fe034

1 file changed

Lines changed: 180 additions & 4 deletions

File tree

ch06/Command.ipynb

Lines changed: 180 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,18 @@
250250
"id": "44ed4c4f6ebba6c"
251251
},
252252
{
253-
"metadata": {},
253+
"metadata": {
254+
"ExecuteTime": {
255+
"end_time": "2026-02-07T09:52:02.484018Z",
256+
"start_time": "2026-02-07T09:52:02.145643Z"
257+
},
258+
"executionRelatedData": {
259+
"compiledClasses": [
260+
"Line_18_jupyter"
261+
]
262+
}
263+
},
254264
"cell_type": "code",
255-
"outputs": [],
256-
"execution_count": null,
257265
"source": [
258266
"class MacroCommand(private val commands: List<Command>) : Command {\n",
259267
" override fun execute() {\n",
@@ -271,7 +279,19 @@
271279
"remote.setCommand(partyMode)\n",
272280
"remote.buttonWasPressed()"
273281
],
274-
"id": "754fc6571262ffc"
282+
"id": "754fc6571262ffc",
283+
"outputs": [
284+
{
285+
"name": "stdout",
286+
"output_type": "stream",
287+
"text": [
288+
"거실 전등이 켜졌습니다.\n",
289+
"주방 오디오가 켜졌습니다.\n",
290+
"주방 오디오 볼륨이 11 로 설정되었습니다.\n"
291+
]
292+
}
293+
],
294+
"execution_count": 16
275295
},
276296
{
277297
"metadata": {},
@@ -284,6 +304,162 @@
284304
"- 매크로 커맨드: 여러 명령을 리스트로 담아 한 번에 실행할 수 있습니다. (예: '취침 모드' 버튼 하나로 전등 끄기 + 커튼 닫기)"
285305
],
286306
"id": "3efcc2c7db3a0008"
307+
},
308+
{
309+
"metadata": {},
310+
"cell_type": "markdown",
311+
"source": [
312+
"## 4. 커맨트 패턴 활용하기\n",
313+
"### (1) 커맨드를 '데이터'처럼 전송하기 (Queue & Log)\n",
314+
"커맨드가 객체가 되면, 지금 즉시 실행하지 않고 **리스트나 큐(Queue)** 에 담아둘 수 있습니다."
315+
],
316+
"id": "1789786fa6b9db99"
317+
},
318+
{
319+
"metadata": {
320+
"executionRelatedData": {
321+
"compiledClasses": [
322+
"Line_19_jupyter",
323+
"Line_20_jupyter"
324+
]
325+
},
326+
"ExecuteTime": {
327+
"end_time": "2026-02-07T10:18:31.416151Z",
328+
"start_time": "2026-02-07T10:18:31.327662Z"
329+
}
330+
},
331+
"cell_type": "code",
332+
"source": [
333+
"// 커맨드들을 담아두는 저장소 (작업 큐)\n",
334+
"val commandQueue = mutableListOf<Command>()\n",
335+
"\n",
336+
"// 작업을 일단 큐에 쌓기\n",
337+
"commandQueue.add(lightOn)\n",
338+
"commandQueue.add(stereoOn)\n",
339+
"\n",
340+
"// 나중에 적절한 시점에 한꺼번에 처리\n",
341+
"println(\"큐에 쌓인 작업들을 처리합니다...\")\n",
342+
"while (commandQueue.isNotEmpty()) {\n",
343+
" val cmd = commandQueue.removeAt(0)\n",
344+
" cmd.execute()\n",
345+
"}"
346+
],
347+
"id": "50c706274c2ecfb0",
348+
"outputs": [
349+
{
350+
"name": "stdout",
351+
"output_type": "stream",
352+
"text": [
353+
"큐에 쌓인 작업들을 처리합니다...\n",
354+
"거실 전등이 켜졌습니다.\n",
355+
"주방 오디오가 켜졌습니다.\n",
356+
"주방 오디오 볼륨이 11 로 설정되었습니다.\n"
357+
]
358+
}
359+
],
360+
"execution_count": 18
361+
},
362+
{
363+
"metadata": {},
364+
"cell_type": "markdown",
365+
"source": [
366+
"### (2) 고차 함수를 이용항 '초경량' 커맨드\n",
367+
"코틀린은 함수 자체가 일급 객체입니다. 따라서 인터페이스 구현체 클래스를 일일이 만들지 않고, **함수 블록 자체를 패키징** 해서 던질 수 있습니다."
368+
],
369+
"id": "49fc6d77b24540b7"
370+
},
371+
{
372+
"metadata": {
373+
"ExecuteTime": {
374+
"end_time": "2026-02-07T10:19:45.090375Z",
375+
"start_time": "2026-02-07T10:19:44.892543Z"
376+
},
377+
"executionRelatedData": {
378+
"compiledClasses": [
379+
"Line_21_jupyter"
380+
]
381+
}
382+
},
383+
"cell_type": "code",
384+
"source": [
385+
"// Invoker: 이제 인터페이스가 아니라 '함수' 자체를 매개변수로 받음\n",
386+
"class LightSwitch {\n",
387+
" fun execute(action: () -> Unit) {\n",
388+
" println(\"작업 실행 전 전처리 중...\")\n",
389+
" action() // 전달받은 계산 조각을 실행\n",
390+
" }\n",
391+
"}\n",
392+
"\n",
393+
"// 사용 시점: 계산 로직(Computation)을 중괄호 { } 안에 묶어서 전달\n",
394+
"val switcher = LightSwitch()\n",
395+
"val kitchenLight = Light(\"주방\")\n",
396+
"\n",
397+
"// '주방 전등 켜기'라는 계산 조각을 패키지로 묶어 전달\n",
398+
"switcher.execute { kitchenLight.on() }"
399+
],
400+
"id": "d6fd10ae0499270",
401+
"outputs": [
402+
{
403+
"name": "stdout",
404+
"output_type": "stream",
405+
"text": [
406+
"작업 실행 전 전처리 중...\n",
407+
"주방 전등이 켜졌습니다.\n"
408+
]
409+
}
410+
],
411+
"execution_count": 19
412+
},
413+
{
414+
"metadata": {},
415+
"cell_type": "markdown",
416+
"source": [
417+
"### (3) 콜백(Callback)과 비동기 처리\n",
418+
"커맨드 객체는 원격 서버나 다른 스레드로 전달하기에도 완벽한 형태입니다. 작업을 요청하는 쪽(Client)과 실행하는 쪽(Worker)이 물리적으로 떨어져 있어도 **'무엇을 할지'** 가 담긴 패키지(Command)만 전달하면 됩니다.\n",
419+
"- 예시: \"데이터 다운로드가 완료되면(Event), 이 커맨드를 실행해줘(Callback).\""
420+
],
421+
"id": "13dc1911c5be3861"
422+
},
423+
{
424+
"metadata": {},
425+
"cell_type": "markdown",
426+
"source": [
427+
"## 자바 스윙 라이브러리\n",
428+
"```Java\n",
429+
"public class SwingObserverExample {\n",
430+
" // 셋업 처리\n",
431+
"\n",
432+
" button.addActioinListener(new AngelListener());\n",
433+
" button.addActioinListener(new DevilListener());\n",
434+
"\n",
435+
" // 프레임 속성 설정\n",
436+
" }\n",
437+
"\n",
438+
" class AngelListener implements ActionListener {\n",
439+
" public void actionPerformed(ActionEvent event) {\n",
440+
" System.out.println(\"하지 마, 후회할걸?\");\n",
441+
" }\n",
442+
" }\n",
443+
"\n",
444+
" class DevilListener implements ActionListener {\n",
445+
" public void actionPerformed(ActionEvent event) {\n",
446+
" System.out.println(\"그냥 저질러 버렷!\");\n",
447+
" }\n",
448+
" }\n",
449+
"}\n",
450+
"```\n",
451+
"1. Command (커맨드 인터페이스) : `ActionListener`\n",
452+
" - `execute()` 대신 `actionPerformed()`라는 메서드를 가진다.\n",
453+
"2. ConcreteCommand (구체적인 커맨드) : `AngelListener`, `DevilListener`\n",
454+
" - `ActionListener` 인터페이스를 실제로 구현한 클래스.\n",
455+
"3. Invoker (호출자) : `JButton`\n",
456+
" - 버튼은 명령을 담을 **슬롯(addActionListener)** 을 가지고 있다. 사용자가 버튼을 클릭하면, 버튼은 자기가 어떤 일을 하는지 몰라도 등록된 커맨드(리스너)의 `actionPerformed()`를 호출한다.\n",
457+
"4. Receiver (수신자) : `System` 객체\n",
458+
" - 커맨드 객체가 `execute()`(여기선 `actionPerformed()`)를 받았을 때 실제로 일을 수행하는 대상\n",
459+
"5. Client (클라이언트) : `SwingObserverExample`\n",
460+
" - 리시버를 결정하고, 커맨드 객체를 생성하여 인보커(버튼)에 전달(등록)하는 전체적인 조립 과정을 담당"
461+
],
462+
"id": "e196100015d9d03b"
287463
}
288464
],
289465
"metadata": {

0 commit comments

Comments
 (0)