@icarusmx/creta 0.11.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/creta.js CHANGED
@@ -8,6 +8,9 @@ import { fileURLToPath } from 'url'
8
8
  import { CretaCodeSession } from '../lib/session.js'
9
9
  import { Lesson1SystemDecomposition } from '../lessons/lesson1-system-decomposition.js'
10
10
  import { Lesson2ObjectRequests } from '../lessons/lesson2-object-requests.js'
11
+ import { Lesson3OnlyWay } from '../lessons/lesson3-only-way.js'
12
+ import { Lesson4OperationSignatures } from '../lessons/lesson4-operation-signatures.js'
13
+ import { Lesson5InterfaceSet } from '../lessons/lesson5-interface-set.js'
11
14
  import { Lesson6InterfaceDesign } from '../lessons/lesson6-interface-design.js'
12
15
 
13
16
  const ENUNCIADOS = [
@@ -856,6 +859,48 @@ async function startEnunciadosSelectorInteractive() {
856
859
  console.log("- Ejercicios prácticos que ilustren el concepto")
857
860
  console.log("- Proyectos específicos para internalizar la idea")
858
861
  }
862
+ } else if (enunciadoSeleccionado.id === 3) {
863
+ console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
864
+ await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
865
+
866
+ try {
867
+ const lesson3 = new Lesson3OnlyWay()
868
+ await lesson3.start()
869
+ } catch (error) {
870
+ console.error("\n❌ Error al ejecutar la lección:", error.message)
871
+ console.log("\n🚀 Próximamente:")
872
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
873
+ console.log("- Ejercicios prácticos que ilustren el concepto")
874
+ console.log("- Proyectos específicos para internalizar la idea")
875
+ }
876
+ } else if (enunciadoSeleccionado.id === 4) {
877
+ console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
878
+ await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
879
+
880
+ try {
881
+ const lesson4 = new Lesson4OperationSignatures()
882
+ await lesson4.start()
883
+ } catch (error) {
884
+ console.error("\n❌ Error al ejecutar la lección:", error.message)
885
+ console.log("\n🚀 Próximamente:")
886
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
887
+ console.log("- Ejercicios prácticos que ilustren el concepto")
888
+ console.log("- Proyectos específicos para internalizar la idea")
889
+ }
890
+ } else if (enunciadoSeleccionado.id === 5) {
891
+ console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
892
+ await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
893
+
894
+ try {
895
+ const lesson5 = new Lesson5InterfaceSet()
896
+ await lesson5.start()
897
+ } catch (error) {
898
+ console.error("\n❌ Error al ejecutar la lección:", error.message)
899
+ console.log("\n🚀 Próximamente:")
900
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
901
+ console.log("- Ejercicios prácticos que ilustren el concepto")
902
+ console.log("- Proyectos específicos para internalizar la idea")
903
+ }
859
904
  } else if (enunciadoSeleccionado.id === 6) {
860
905
  console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
861
906
  await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
@@ -987,6 +1032,54 @@ async function startEnunciadosSelectorFallback() {
987
1032
  console.log("- Proyectos específicos para internalizar la idea")
988
1033
  }
989
1034
  return
1035
+ } else if (enunciadoSeleccionado.id === 3) {
1036
+ console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
1037
+ rl.close()
1038
+ await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
1039
+
1040
+ try {
1041
+ const lesson3 = new Lesson3OnlyWay()
1042
+ await lesson3.start()
1043
+ } catch (error) {
1044
+ console.error("\n❌ Error al ejecutar la lección:", error.message)
1045
+ console.log("\n🚀 Próximamente:")
1046
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
1047
+ console.log("- Ejercicios prácticos que ilustren el concepto")
1048
+ console.log("- Proyectos específicos para internalizar la idea")
1049
+ }
1050
+ return
1051
+ } else if (enunciadoSeleccionado.id === 4) {
1052
+ console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
1053
+ rl.close()
1054
+ await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
1055
+
1056
+ try {
1057
+ const lesson4 = new Lesson4OperationSignatures()
1058
+ await lesson4.start()
1059
+ } catch (error) {
1060
+ console.error("\n❌ Error al ejecutar la lección:", error.message)
1061
+ console.log("\n🚀 Próximamente:")
1062
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
1063
+ console.log("- Ejercicios prácticos que ilustren el concepto")
1064
+ console.log("- Proyectos específicos para internalizar la idea")
1065
+ }
1066
+ return
1067
+ } else if (enunciadoSeleccionado.id === 5) {
1068
+ console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
1069
+ rl.close()
1070
+ await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
1071
+
1072
+ try {
1073
+ const lesson5 = new Lesson5InterfaceSet()
1074
+ await lesson5.start()
1075
+ } catch (error) {
1076
+ console.error("\n❌ Error al ejecutar la lección:", error.message)
1077
+ console.log("\n🚀 Próximamente:")
1078
+ console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
1079
+ console.log("- Ejercicios prácticos que ilustren el concepto")
1080
+ console.log("- Proyectos específicos para internalizar la idea")
1081
+ }
1082
+ return
990
1083
  } else if (enunciadoSeleccionado.id === 6) {
991
1084
  console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
992
1085
  rl.close()
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env node
2
+
3
+ // LECCIÓN 3: Las solicitudes son la única forma de conseguir que un objeto lleve a cabo una operación
4
+ // Enfoque práctico: Demostrar que NO hay alternativas a las solicitudes para ejecutar operaciones
5
+
6
+ import { createInterface } from 'readline'
7
+
8
+ export class Lesson3OnlyWay {
9
+ constructor() {
10
+ this.rl = createInterface({
11
+ input: process.stdin,
12
+ output: process.stdout
13
+ })
14
+ }
15
+
16
+ async start() {
17
+ console.log("🎯 LECCIÓN 3: Solicitudes como Única Forma")
18
+ console.log("=" .repeat(50))
19
+ console.log("📚 Enunciado: Las solicitudes son la única forma de conseguir que un objeto lleve a cabo una operación.")
20
+ console.log("\n💡 ¿Por qué ÚNICA forma?")
21
+ console.log("- No puedes forzar a un objeto a ejecutar algo")
22
+ console.log("- No puedes manipular directamente su estado interno")
23
+ console.log("- Toda operación DEBE pasar por una solicitud")
24
+ console.log("- El objeto decide si acepta o rechaza la solicitud")
25
+
26
+ await this.waitForEnter("\nPresiona Enter para ver qué significa esto en la práctica...")
27
+
28
+ await this.practicalExercise()
29
+ await this.conclusion()
30
+
31
+ this.rl.close()
32
+ }
33
+
34
+ async practicalExercise() {
35
+ console.clear()
36
+ console.log("🛠️ EJERCICIO PRÁCTICO: Caja Fuerte Digital")
37
+ console.log("=" .repeat(50))
38
+ console.log("🎯 Vamos a demostrar por qué las solicitudes son la ÚNICA forma")
39
+ console.log("\nSistema: Una caja fuerte que protege documentos importantes")
40
+ console.log("Objeto: DigitalSafe")
41
+
42
+ await this.waitForEnter("\nPresiona Enter para ver todas las formas que NO funcionan...")
43
+
44
+ await this.step1_ShowWhatDoesntWork()
45
+ await this.step2_ShowOnlyWay()
46
+ await this.step3_ObjectDecision()
47
+ await this.step4_CompleteDemo()
48
+ }
49
+
50
+ async step1_ShowWhatDoesntWork() {
51
+ console.clear()
52
+ console.log("❌ FORMAS QUE NO FUNCIONAN")
53
+ console.log("=" .repeat(35))
54
+ console.log("Veamos todas las cosas que NO puedes hacer:")
55
+
56
+ console.log("\n🚫 1. ACCESO DIRECTO A DATOS (Imposible)")
57
+ console.log(`// ❌ Esto NO funciona en objetos bien diseñados
58
+ class DigitalSafe {
59
+ constructor() {
60
+ this.#documents = [] // PRIVADO
61
+ this.#isLocked = true // PRIVADO
62
+ this.#password = "1234" // PRIVADO
63
+ }
64
+ }
65
+
66
+ const safe = new DigitalSafe()
67
+ // ❌ ERROR: No puedes acceder a datos privados
68
+ console.log(safe.#documents) // SyntaxError!
69
+ safe.#isLocked = false // SyntaxError!`)
70
+
71
+ await this.waitForEnter("\nPresiona Enter para ver más formas que no funcionan...")
72
+
73
+ console.log("\n🚫 2. MANIPULACIÓN EXTERNA (Imposible)")
74
+ console.log(`// ❌ No puedes forzar cambios desde afuera
75
+ safe.documents = ["documento_falso.pdf"] // undefined (no existe)
76
+ safe.isLocked = false // undefined (no existe)
77
+ safe.forceOpen() // TypeError: no es función
78
+
79
+ // ❌ No puedes inyectar funciones
80
+ safe.hackOpen = function() { this.#isLocked = false } // No funciona`)
81
+
82
+ await this.waitForEnter("\nPresiona Enter para ver la última forma que no funciona...")
83
+
84
+ console.log("\n🚫 3. HERENCIA FORZADA (Violación de diseño)")
85
+ console.log(`// ❌ Incluso extendiendo la clase, no puedes saltarte las reglas
86
+ class HackedSafe extends DigitalSafe {
87
+ forceOpen() {
88
+ // ❌ ERROR: No puedes acceder a campos privados del padre
89
+ this.#isLocked = false // SyntaxError!
90
+ return this.#documents // SyntaxError!
91
+ }
92
+ }`)
93
+
94
+ console.log("\n💡 Observación clave:")
95
+ console.log("El objeto está completamente protegido. No hay forma de")
96
+ console.log("manipularlo externamente sin su consentimiento.")
97
+
98
+ await this.waitForEnter("\nPresiona Enter para ver la ÚNICA forma que funciona...")
99
+ }
100
+
101
+ async step2_ShowOnlyWay() {
102
+ console.clear()
103
+ console.log("✅ LA ÚNICA FORMA: SOLICITUDES")
104
+ console.log("=" .repeat(40))
105
+ console.log("Solo hay UNA manera de que el objeto ejecute operaciones:")
106
+
107
+ console.log("\n🔑 IMPLEMENTACIÓN COMPLETA:")
108
+ console.log(`class DigitalSafe {
109
+ constructor() {
110
+ this.#documents = []
111
+ this.#isLocked = true
112
+ this.#password = "1234"
113
+ this.#attempts = 0
114
+ this.#maxAttempts = 3
115
+ }
116
+
117
+ // ✅ SOLICITUD: Intentar desbloquear
118
+ unlock(password) {
119
+ if (this.#attempts >= this.#maxAttempts) {
120
+ return { success: false, message: "Bloqueado por seguridad" }
121
+ }
122
+
123
+ if (password === this.#password) {
124
+ this.#isLocked = false
125
+ this.#attempts = 0
126
+ return { success: true, message: "Caja fuerte desbloqueada" }
127
+ } else {
128
+ this.#attempts++
129
+ return {
130
+ success: false,
131
+ message: \`Contraseña incorrecta. Intentos restantes: \${this.#maxAttempts - this.#attempts}\`
132
+ }
133
+ }
134
+ }
135
+
136
+ // ✅ SOLICITUD: Agregar documento
137
+ addDocument(document) {
138
+ if (this.#isLocked) {
139
+ return { success: false, message: "Caja fuerte bloqueada" }
140
+ }
141
+
142
+ this.#documents.push(document)
143
+ return { success: true, message: "Documento agregado" }
144
+ }
145
+
146
+ // ✅ SOLICITUD: Obtener documentos
147
+ getDocuments() {
148
+ if (this.#isLocked) {
149
+ return { success: false, message: "Caja fuerte bloqueada", documents: [] }
150
+ }
151
+
152
+ return { success: true, documents: [...this.#documents] }
153
+ }
154
+
155
+ // ✅ SOLICITUD: Bloquear
156
+ lock() {
157
+ this.#isLocked = true
158
+ return { success: true, message: "Caja fuerte bloqueada" }
159
+ }
160
+
161
+ // ✅ SOLICITUD: Consultar estado
162
+ getStatus() {
163
+ return {
164
+ isLocked: this.#isLocked,
165
+ documentsCount: this.#documents.length,
166
+ attemptsRemaining: this.#maxAttempts - this.#attempts
167
+ }
168
+ }
169
+ }`)
170
+
171
+ await this.waitForEnter("\nPresiona Enter para ver por qué esto es la ÚNICA forma...")
172
+ }
173
+
174
+ async step3_ObjectDecision() {
175
+ console.clear()
176
+ console.log("🧠 EL OBJETO DECIDE")
177
+ console.log("=" .repeat(25))
178
+ console.log("Observa que cada solicitud permite al objeto DECIDIR:")
179
+
180
+ console.log("\n🔍 EJEMPLO 1: Solicitud aceptada")
181
+ console.log(`const safe = new DigitalSafe()
182
+
183
+ // SOLICITUD: unlock con contraseña correcta
184
+ const result = safe.unlock("1234")
185
+ console.log(result) // { success: true, message: "Caja fuerte desbloqueada" }
186
+
187
+ // El OBJETO decidió aceptar la solicitud porque:
188
+ // - La contraseña era correcta
189
+ // - No se habían agotado los intentos`)
190
+
191
+ await this.waitForEnter("\nPresiona Enter para ver una solicitud rechazada...")
192
+
193
+ console.log("\n🚫 EJEMPLO 2: Solicitud rechazada")
194
+ console.log(`// SOLICITUD: addDocument sin desbloquear
195
+ const result2 = safe.addDocument("documento_secreto.pdf")
196
+ console.log(result2) // { success: false, message: "Caja fuerte bloqueada" }
197
+
198
+ // El OBJETO decidió rechazar la solicitud porque:
199
+ // - La caja fuerte está bloqueada
200
+ // - No cumple las condiciones internas`)
201
+
202
+ await this.waitForEnter("\nPresiona Enter para ver el control total del objeto...")
203
+
204
+ console.log("\n🛡️ EJEMPLO 3: Protección automática")
205
+ console.log(`// Intentos fallidos múltiples
206
+ safe.unlock("wrong1") // { success: false, message: "Contraseña incorrecta..." }
207
+ safe.unlock("wrong2") // { success: false, message: "Contraseña incorrecta..." }
208
+ safe.unlock("wrong3") // { success: false, message: "Contraseña incorrecta..." }
209
+ safe.unlock("1234") // { success: false, message: "Bloqueado por seguridad" }
210
+
211
+ // El OBJETO decidió bloquearse completamente porque:
212
+ // - Se agotaron los intentos permitidos
213
+ // - Sus reglas internas de seguridad se activaron`)
214
+
215
+ console.log("\n💡 Punto clave:")
216
+ console.log("Incluso con la contraseña correcta, el objeto puede rechazar")
217
+ console.log("la solicitud si sus condiciones internas no se cumplen.")
218
+
219
+ await this.waitForEnter("\nPresiona Enter para la demostración completa...")
220
+ }
221
+
222
+ async step4_CompleteDemo() {
223
+ console.clear()
224
+ console.log("🎭 DEMOSTRACIÓN: Flujo Completo")
225
+ console.log("=" .repeat(40))
226
+ console.log("Veamos un flujo completo de solicitudes:")
227
+
228
+ console.log("\n// Crear caja fuerte")
229
+ console.log("const safe = new DigitalSafe()")
230
+ console.log("")
231
+ console.log("// 🔍 SOLICITUD: Consultar estado inicial")
232
+ console.log("console.log(safe.getStatus())")
233
+ console.log("// { isLocked: true, documentsCount: 0, attemptsRemaining: 3 }")
234
+ console.log("")
235
+ console.log("// 🚫 SOLICITUD: Intentar agregar documento (será rechazada)")
236
+ console.log("safe.addDocument('mi_testamento.pdf')")
237
+ console.log("// { success: false, message: 'Caja fuerte bloqueada' }")
238
+ console.log("")
239
+ console.log("// 🔑 SOLICITUD: Desbloquear")
240
+ console.log("safe.unlock('1234')")
241
+ console.log("// { success: true, message: 'Caja fuerte desbloqueada' }")
242
+ console.log("")
243
+ console.log("// ✅ SOLICITUD: Ahora sí agregar documento")
244
+ console.log("safe.addDocument('mi_testamento.pdf')")
245
+ console.log("// { success: true, message: 'Documento agregado' }")
246
+ console.log("")
247
+ console.log("safe.addDocument('contrato_importante.pdf')")
248
+ console.log("// { success: true, message: 'Documento agregado' }")
249
+
250
+ await this.waitForEnter("\nPresiona Enter para ver la recuperación...")
251
+
252
+ console.log("\n// 📄 SOLICITUD: Recuperar documentos")
253
+ console.log("const docs = safe.getDocuments()")
254
+ console.log("console.log(docs)")
255
+ console.log("// { success: true, documents: ['mi_testamento.pdf', 'contrato_importante.pdf'] }")
256
+ console.log("")
257
+ console.log("// 🔒 SOLICITUD: Bloquear nuevamente")
258
+ console.log("safe.lock()")
259
+ console.log("// { success: true, message: 'Caja fuerte bloqueada' }")
260
+ console.log("")
261
+ console.log("// 🚫 SOLICITUD: Intentar recuperar (será rechazada)")
262
+ console.log("safe.getDocuments()")
263
+ console.log("// { success: false, message: 'Caja fuerte bloqueada', documents: [] }")
264
+
265
+ console.log("\n🎯 Observaciones finales:")
266
+ console.log("• Cada operación requirió una SOLICITUD específica")
267
+ console.log("• El objeto controló completamente qué solicitudes aceptar")
268
+ console.log("• No hubo forma de saltarse este mecanismo")
269
+ console.log("• Las solicitudes son verdaderamente la ÚNICA forma")
270
+
271
+ await this.waitForEnter("\nPresiona Enter para la conclusión...")
272
+ }
273
+
274
+ async conclusion() {
275
+ console.clear()
276
+ console.log("🎓 CONCLUSIÓN: Solicitudes como Única Forma")
277
+ console.log("=" .repeat(50))
278
+ console.log("🎯 Hemos demostrado que:")
279
+
280
+ console.log("\n1️⃣ NO es posible acceder directamente a datos privados")
281
+ console.log("2️⃣ NO es posible manipular el objeto externamente")
282
+ console.log("3️⃣ NO es posible forzar operaciones sin consentimiento")
283
+ console.log("4️⃣ Las SOLICITUDES son literalmente la única forma")
284
+
285
+ console.log("\n🔑 Características de las solicitudes:")
286
+ console.log("• El objeto DECIDE si acepta o rechaza")
287
+ console.log("• Cada solicitud pasa por validaciones internas")
288
+ console.log("• El objeto mantiene control total de su estado")
289
+ console.log("• Las reglas internas se respetan siempre")
290
+
291
+ console.log("\n🛡️ Beneficios de este diseño:")
292
+ console.log("• Seguridad garantizada")
293
+ console.log("• Integridad de datos preservada")
294
+ console.log("• Comportamiento predecible")
295
+ console.log("• Control total del objeto sobre sí mismo")
296
+
297
+ console.log("\n📚 Conexión con otras lecciones:")
298
+ console.log("• Lección 1: Los objetos que identificamos tienen este comportamiento")
299
+ console.log("• Lección 2: Esas interacciones son siempre solicitudes")
300
+ console.log("• Lección 3: ✅ Y son la ÚNICA forma de ejecutar operaciones")
301
+ console.log("• Lecciones 4-6: Cómo definir formalmente estas solicitudes")
302
+
303
+ console.log("\n💭 Reflexión:")
304
+ console.log("Imagina que tu casa tuviera esta protección: nadie puede entrar")
305
+ console.log("a menos que tú decidas abrir la puerta después de verificar")
306
+ console.log("quién es. Los objetos funcionan exactamente igual.")
307
+
308
+ console.log("\n🏆 Ahora entiendes por qué las solicitudes son la ÚNICA forma:")
309
+ console.log("porque los objetos están diseñados para protegerse y decidir.")
310
+
311
+ await this.waitForEnter("\n✨ ¡Lección 3 completada! Presiona Enter para salir...")
312
+ }
313
+
314
+ async waitForEnter(message) {
315
+ return new Promise((resolve) => {
316
+ this.rl.question(message, () => {
317
+ resolve()
318
+ })
319
+ })
320
+ }
321
+ }
322
+
323
+ // Para usar la lección independientemente
324
+ if (import.meta.url === `file://${process.argv[1]}`) {
325
+ const lesson = new Lesson3OnlyWay()
326
+ await lesson.start()
327
+ }
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env node
2
+
3
+ // LECCIÓN 4: Cada operación declarada por un objeto debe incluir: a) nombre de la operación; b) insumos necesarios para realizar la operación; c) el valor que regresa tras ejecutar la operación. Estos tres elementos constituyen la firma de operación.
4
+ // Enfoque práctico: Diseñar firmas de operación precisas y completas
5
+
6
+ import { createInterface } from 'readline'
7
+
8
+ export class Lesson4OperationSignatures {
9
+ constructor() {
10
+ this.rl = createInterface({
11
+ input: process.stdin,
12
+ output: process.stdout
13
+ })
14
+ }
15
+
16
+ async start() {
17
+ console.log("🎯 LECCIÓN 4: Firmas de Operación")
18
+ console.log("=" .repeat(50))
19
+ console.log("📚 Enunciado: Cada operación declarada por un objeto debe incluir:")
20
+ console.log(" a) nombre de la operación")
21
+ console.log(" b) insumos necesarios para realizar la operación")
22
+ console.log(" c) el valor que regresa tras ejecutar la operación")
23
+ console.log(" Estos tres elementos constituyen la firma de operación.")
24
+
25
+ console.log("\n💡 ¿Por qué son importantes las firmas?")
26
+ console.log("- Define exactamente QUÉ hace la operación (nombre)")
27
+ console.log("- Define exactamente QUÉ necesita (insumos)")
28
+ console.log("- Define exactamente QUÉ devuelve (valor de retorno)")
29
+ console.log("- Permite predecir el comportamiento sin ver la implementación")
30
+
31
+ await this.waitForEnter("\nPresiona Enter para comenzar con ejemplos prácticos...")
32
+
33
+ await this.practicalExercise()
34
+ await this.conclusion()
35
+
36
+ this.rl.close()
37
+ }
38
+
39
+ async practicalExercise() {
40
+ console.clear()
41
+ console.log("🛠️ EJERCICIO PRÁCTICO: Calculadora Financiera")
42
+ console.log("=" .repeat(50))
43
+ console.log("🎯 Vamos a diseñar firmas de operación precisas y completas")
44
+ console.log("\nSistema: Calculadora para operaciones financieras")
45
+ console.log("Objeto: FinancialCalculator")
46
+
47
+ await this.waitForEnter("\nPresiona Enter para ver firmas mal diseñadas...")
48
+
49
+ await this.step1_BadSignatures()
50
+ await this.step2_GoodSignatures()
51
+ await this.step3_SignatureAnalysis()
52
+ await this.step4_CompleteExample()
53
+ }
54
+
55
+ async step1_BadSignatures() {
56
+ console.clear()
57
+ console.log("❌ FIRMAS MAL DISEÑADAS")
58
+ console.log("=" .repeat(30))
59
+ console.log("Veamos firmas incompletas o confusas:")
60
+
61
+ console.log("\n🚫 PROBLEMA 1: Nombre poco claro")
62
+ console.log(`// ❌ ¿Qué hace exactamente 'calc'?
63
+ calc(x, y) → ?
64
+
65
+ // ❌ ¿Es 'do' suma, resta, multiplicación?
66
+ do(amount, rate) → ?`)
67
+
68
+ console.log("\n🚫 PROBLEMA 2: Insumos ambiguos")
69
+ console.log(`// ❌ ¿Qué tipo de datos espera?
70
+ calculateInterest(amount, rate) → number
71
+ // ¿amount es string o number?
72
+ // ¿rate es porcentaje (0.05) o entero (5)?`)
73
+
74
+ console.log("\n🚫 PROBLEMA 3: Valor de retorno incierto")
75
+ console.log(`// ❌ ¿Qué devuelve exactamente?
76
+ calculatePayment() → ?
77
+ // ¿Un número? ¿Un objeto? ¿null si falla?
78
+
79
+ // ❌ ¿Y si hay error?
80
+ divideNumbers(a, b) → number
81
+ // ¿Qué pasa si b es 0?`)
82
+
83
+ await this.waitForEnter("\nPresiona Enter para ver más problemas...")
84
+
85
+ console.log("\n🚫 PROBLEMA 4: Firmas inconsistentes")
86
+ console.log(`// ❌ Métodos similares con firmas diferentes
87
+ addMoney(amount) → boolean
88
+ subtractCash(value, currency) → {success: boolean, balance: number}
89
+ multiply(x, y, precision) → number | null
90
+
91
+ // ❌ Imposible predecir qué esperar de cada método`)
92
+
93
+ console.log("\n💥 Consecuencias:")
94
+ console.log("• Imposible usar el objeto sin ver el código interno")
95
+ console.log("• Errores constantes por malentender los parámetros")
96
+ console.log("• Código frágil y difícil de mantener")
97
+ console.log("• Colaboración entre objetos impredecible")
98
+
99
+ await this.waitForEnter("\nPresiona Enter para ver cómo debe ser...")
100
+ }
101
+
102
+ async step2_GoodSignatures() {
103
+ console.clear()
104
+ console.log("✅ FIRMAS BIEN DISEÑADAS")
105
+ console.log("=" .repeat(35))
106
+ console.log("Ahora veamos firmas completas y precisas:")
107
+
108
+ console.log("\n🎯 ELEMENTO A: Nombre claro y específico")
109
+ console.log(`// ✅ Nombres que describen exactamente la operación
110
+ calculateSimpleInterest(principal, rate, time) → number
111
+ calculateCompoundInterest(principal, rate, time, frequency) → number
112
+ calculateMonthlyPayment(loanAmount, interestRate, termInMonths) → number`)
113
+
114
+ console.log("\n📥 ELEMENTO B: Insumos específicos y tipados")
115
+ console.log(`// ✅ Cada parámetro claramente definido
116
+ calculateSimpleInterest(
117
+ principal: number, // Monto principal en pesos
118
+ rate: number, // Tasa anual como decimal (0.05 = 5%)
119
+ time: number // Tiempo en años
120
+ ) → number
121
+
122
+ calculateMonthlyPayment(
123
+ loanAmount: number, // Monto del préstamo en pesos
124
+ interestRate: number, // Tasa mensual como decimal
125
+ termInMonths: number // Plazo en meses
126
+ ) → number`)
127
+
128
+ console.log("\n📤 ELEMENTO C: Valor de retorno específico")
129
+ console.log(`// ✅ Especifica exactamente qué devuelve y cuándo
130
+ calculateLoanPayment(amount, rate, term) → {
131
+ success: boolean,
132
+ monthlyPayment: number | null,
133
+ totalInterest: number | null,
134
+ error: string | null
135
+ }
136
+
137
+ validateLoanAmount(amount) → {
138
+ isValid: boolean,
139
+ minimumRequired: number,
140
+ maximumAllowed: number
141
+ }`)
142
+
143
+ await this.waitForEnter("\nPresiona Enter para ver la implementación completa...")
144
+ }
145
+
146
+ async step3_SignatureAnalysis() {
147
+ console.clear()
148
+ console.log("🔍 ANÁLISIS DE FIRMAS COMPLETAS")
149
+ console.log("=" .repeat(40))
150
+ console.log("Examinemos cada elemento de las firmas:")
151
+
152
+ console.log("\n💼 EJEMPLO: Calculadora financiera completa")
153
+ console.log(`class FinancialCalculator {
154
+ // 🎯 FIRMA 1: Interés simple
155
+ calculateSimpleInterest(
156
+ principal: number, // a) Monto principal en pesos
157
+ rate: number, // b) Tasa anual (0.05 = 5%)
158
+ time: number // c) Tiempo en años
159
+ ): number { // RETORNA: Interés total calculado
160
+ return principal * rate * time
161
+ }
162
+
163
+ // 🎯 FIRMA 2: Validación con resultado estructurado
164
+ validateLoanApplication(
165
+ income: number, // a) Ingreso mensual
166
+ existingDebt: number, // b) Deuda actual
167
+ requestedAmount: number // c) Monto solicitado
168
+ ): { // RETORNA: Objeto con análisis completo
169
+ approved: boolean,
170
+ maxLoanAmount: number,
171
+ debtToIncomeRatio: number,
172
+ reasons: string[]
173
+ }
174
+
175
+ // 🎯 FIRMA 3: Cálculo que puede fallar
176
+ calculateCompoundInterest(
177
+ principal: number, // a) Monto principal
178
+ rate: number, // b) Tasa anual
179
+ time: number, // c) Años
180
+ frequency: number // d) Frecuencia de composición
181
+ ): number | null { // RETORNA: Resultado o null si hay error
182
+ if (principal <= 0 || rate < 0 || time <= 0 || frequency <= 0) {
183
+ return null
184
+ }
185
+ return principal * Math.pow(1 + rate/frequency, frequency * time)
186
+ }
187
+ }`)
188
+
189
+ await this.waitForEnter("\nPresiona Enter para analizar cada firma...")
190
+
191
+ console.log("\n📋 ANÁLISIS FIRMA POR FIRMA:")
192
+ console.log("\n1️⃣ calculateSimpleInterest:")
193
+ console.log(" • NOMBRE: 'calculateSimpleInterest' - claro y específico")
194
+ console.log(" • INSUMOS: (principal, rate, time) - 3 números con propósito definido")
195
+ console.log(" • RETORNO: number - interés calculado, siempre un número")
196
+
197
+ console.log("\n2️⃣ validateLoanApplication:")
198
+ console.log(" • NOMBRE: 'validateLoanApplication' - describe validación completa")
199
+ console.log(" • INSUMOS: (income, existingDebt, requestedAmount) - datos financieros")
200
+ console.log(" • RETORNO: objeto estructurado - análisis completo con múltiples campos")
201
+
202
+ console.log("\n3️⃣ calculateCompoundInterest:")
203
+ console.log(" • NOMBRE: 'calculateCompoundInterest' - específico del tipo de interés")
204
+ console.log(" • INSUMOS: (principal, rate, time, frequency) - 4 parámetros necesarios")
205
+ console.log(" • RETORNO: number | null - puede fallar si datos inválidos")
206
+
207
+ await this.waitForEnter("\nPresiona Enter para ver cómo usar estas firmas...")
208
+ }
209
+
210
+ async step4_CompleteExample() {
211
+ console.clear()
212
+ console.log("🎭 DEMOSTRACIÓN: Uso con Firmas Claras")
213
+ console.log("=" .repeat(45))
214
+ console.log("Veamos cómo las firmas bien diseñadas facilitan el uso:")
215
+
216
+ console.log("\n// Crear calculadora")
217
+ console.log("const calc = new FinancialCalculator()")
218
+ console.log("")
219
+ console.log("// 💡 Con las firmas claras, sabemos exactamente qué esperar:")
220
+ console.log("")
221
+ console.log("// FIRMA: calculateSimpleInterest(principal, rate, time) → number")
222
+ console.log("const interest = calc.calculateSimpleInterest(10000, 0.05, 2)")
223
+ console.log("console.log(interest) // 1000 (siempre un número)")
224
+
225
+ await this.waitForEnter("\nPresiona Enter para ver validación...")
226
+
227
+ console.log("\n// FIRMA: validateLoanApplication(income, debt, amount) → objeto")
228
+ console.log("const validation = calc.validateLoanApplication(5000, 1000, 50000)")
229
+ console.log("console.log(validation)")
230
+ console.log("// {")
231
+ console.log("// approved: false,")
232
+ console.log("// maxLoanAmount: 20000,")
233
+ console.log("// debtToIncomeRatio: 0.2,")
234
+ console.log("// reasons: ['Monto solicitado excede capacidad de pago']")
235
+ console.log("// }")
236
+ console.log("")
237
+ console.log("// 💡 Podemos usar cada campo porque la firma nos dice qué esperar")
238
+ console.log("if (validation.approved) {")
239
+ console.log(" console.log('Préstamo aprobado!')")
240
+ console.log("} else {")
241
+ console.log(" console.log('Máximo permitido:', validation.maxLoanAmount)")
242
+ console.log(" validation.reasons.forEach(reason => console.log('❌', reason))")
243
+ console.log("}")
244
+
245
+ await this.waitForEnter("\nPresiona Enter para ver manejo de errores...")
246
+
247
+ console.log("\n// FIRMA: calculateCompoundInterest(...) → number | null")
248
+ console.log("const compound1 = calc.calculateCompoundInterest(10000, 0.05, 2, 12)")
249
+ console.log("const compound2 = calc.calculateCompoundInterest(-1000, 0.05, 2, 12)")
250
+ console.log("")
251
+ console.log("// 💡 La firma nos dice que puede retornar null, así que verificamos")
252
+ console.log("if (compound1 !== null) {")
253
+ console.log(" console.log('Interés compuesto:', compound1) // 11049.41")
254
+ console.log("}")
255
+ console.log("")
256
+ console.log("if (compound2 === null) {")
257
+ console.log(" console.log('Error: datos inválidos') // Se ejecuta")
258
+ console.log("}")
259
+
260
+ console.log("\n🎯 Beneficios observados:")
261
+ console.log("• Sabemos exactamente qué pasar a cada método")
262
+ console.log("• Sabemos exactamente qué esperar de vuelta")
263
+ console.log("• Podemos manejar errores apropiadamente")
264
+ console.log("• El código es predecible y confiable")
265
+
266
+ await this.waitForEnter("\nPresiona Enter para la conclusión...")
267
+ }
268
+
269
+ async conclusion() {
270
+ console.clear()
271
+ console.log("🎓 CONCLUSIÓN: Firmas de Operación")
272
+ console.log("=" .repeat(40))
273
+ console.log("🎯 Hemos demostrado que cada firma debe incluir:")
274
+
275
+ console.log("\n🎯 A) NOMBRE de la operación:")
276
+ console.log(" • Claro y específico")
277
+ console.log(" • Describe exactamente qué hace")
278
+ console.log(" • Ejemplo: 'calculateSimpleInterest' vs 'calc'")
279
+
280
+ console.log("\n📥 B) INSUMOS necesarios:")
281
+ console.log(" • Tipo y propósito de cada parámetro")
282
+ console.log(" • Valores esperados y restricciones")
283
+ console.log(" • Ejemplo: 'rate: number (decimal, 0.05 = 5%)'")
284
+
285
+ console.log("\n📤 C) VALOR de retorno:")
286
+ console.log(" • Tipo exacto que retorna")
287
+ console.log(" • Qué significa el valor")
288
+ console.log(" • Cómo manejar casos de error")
289
+ console.log(" • Ejemplo: 'number | null' vs solo 'number'")
290
+
291
+ console.log("\n🌟 Beneficios de firmas completas:")
292
+ console.log("• Predictibilidad total del comportamiento")
293
+ console.log("• Colaboración segura entre objetos")
294
+ console.log("• Código autodocumentado")
295
+ console.log("• Detección temprana de errores")
296
+
297
+ console.log("\n📚 Conexión con otras lecciones:")
298
+ console.log("• Lección 1-3: Las operaciones que identificamos necesitan firmas")
299
+ console.log("• Lección 4: ✅ Cada operación tiene nombre, insumos y retorno")
300
+ console.log("• Lección 5: El conjunto de firmas forma la interfaz")
301
+ console.log("• Lección 6: El énfasis está en diseñar estas firmas primero")
302
+
303
+ console.log("\n💭 Reflexión:")
304
+ console.log("¿Te imaginas usar una función de la que no sabes qué parámetros")
305
+ console.log("espera ni qué devuelve? ¡Sería imposible! Las firmas son el")
306
+ console.log("contrato que hace posible la colaboración entre objetos.")
307
+
308
+ console.log("\n🏆 Ahora entiendes por qué cada operación necesita una firma")
309
+ console.log("completa: es la base de la comunicación predecible.")
310
+
311
+ await this.waitForEnter("\n✨ ¡Lección 4 completada! Presiona Enter para salir...")
312
+ }
313
+
314
+ async waitForEnter(message) {
315
+ return new Promise((resolve) => {
316
+ this.rl.question(message, () => {
317
+ resolve()
318
+ })
319
+ })
320
+ }
321
+ }
322
+
323
+ // Para usar la lección independientemente
324
+ if (import.meta.url === `file://${process.argv[1]}`) {
325
+ const lesson = new Lesson4OperationSignatures()
326
+ await lesson.start()
327
+ }
@@ -0,0 +1,330 @@
1
+ #!/usr/bin/env node
2
+
3
+ // LECCIÓN 5: La interfaz de un objeto es el conjunto de todas sus firmas de operación
4
+ // Enfoque práctico: Demostrar cómo las firmas individuales forman una interfaz coherente
5
+
6
+ import { createInterface } from 'readline'
7
+
8
+ export class Lesson5InterfaceSet {
9
+ constructor() {
10
+ this.rl = createInterface({
11
+ input: process.stdin,
12
+ output: process.stdout
13
+ })
14
+ }
15
+
16
+ async start() {
17
+ console.log("🎯 LECCIÓN 5: Interfaz como Conjunto de Firmas")
18
+ console.log("=" .repeat(50))
19
+ console.log("📚 Enunciado: La interfaz de un objeto es el conjunto de todas sus firmas de operación.")
20
+
21
+ console.log("\n💡 ¿Qué significa esto?")
22
+ console.log("- Una interfaz NO es una sola operación")
23
+ console.log("- Es el CONJUNTO COMPLETO de todas las firmas")
24
+ console.log("- Define TODO lo que el objeto puede hacer")
25
+ console.log("- Es el 'contrato público' del objeto")
26
+
27
+ await this.waitForEnter("\nPresiona Enter para comenzar con ejemplos prácticos...")
28
+
29
+ await this.practicalExercise()
30
+ await this.conclusion()
31
+
32
+ this.rl.close()
33
+ }
34
+
35
+ async practicalExercise() {
36
+ console.clear()
37
+ console.log("🛠️ EJERCICIO PRÁCTICO: Reproductor de Música")
38
+ console.log("=" .repeat(50))
39
+ console.log("🎯 Vamos a construir una interfaz completa paso a paso")
40
+ console.log("\nSistema: Reproductor de música digital")
41
+ console.log("Objeto: MusicPlayer")
42
+
43
+ await this.waitForEnter("\nPresiona Enter para ver cómo NO diseñar una interfaz...")
44
+
45
+ await this.step1_IncompleteInterface()
46
+ await this.step2_CompleteInterface()
47
+ await this.step3_InterfaceCoherence()
48
+ await this.step4_InterfaceUsage()
49
+ }
50
+
51
+ async step1_IncompleteInterface() {
52
+ console.clear()
53
+ console.log("❌ INTERFAZ INCOMPLETA")
54
+ console.log("=" .repeat(30))
55
+ console.log("Veamos un objeto con interfaz parcial:")
56
+
57
+ console.log("\n🚫 PROBLEMA: Solo algunas operaciones definidas")
58
+ console.log(`class MusicPlayer {
59
+ // ✅ Operación bien definida
60
+ play(songId: string): boolean {
61
+ // implementación...
62
+ }
63
+
64
+ // ❌ Otras operaciones sin firma clara
65
+ stop() {
66
+ // ¿Qué devuelve? ¿Puede fallar?
67
+ }
68
+
69
+ volume(level) {
70
+ // ¿Qué tipo es level? ¿Qué rango?
71
+ }
72
+
73
+ // ❌ Operaciones faltantes
74
+ // ¿Cómo pauso? ¿Cómo cambio de canción?
75
+ // ¿Cómo consulto qué está sonando?
76
+ }`)
77
+
78
+ console.log("\n💥 Problemas de interfaz incompleta:")
79
+ console.log("• Imposible predecir qué operaciones están disponibles")
80
+ console.log("• Firmas inconsistentes entre operaciones")
81
+ console.log("• Funcionalidad básica faltante")
82
+ console.log("• Colaboración con otros objetos impredecible")
83
+
84
+ await this.waitForEnter("\nPresiona Enter para ver otro problema...")
85
+
86
+ console.log("\n🚫 PROBLEMA: Firmas sin relación")
87
+ console.log(`class BadMusicPlayer {
88
+ // ❌ Firmas que no forman un conjunto coherente
89
+ startMusic(file: string): void // Usa archivos
90
+ playTrack(id: number): boolean // Usa IDs numéricos
91
+ beginSong(song: object): string // Usa objetos
92
+
93
+ setVol(x: number): void // Volumen sin validación
94
+ adjustAudio(level: string): boolean // Volumen como string??
95
+
96
+ getCurrentStatus(): any // Retorna 'any' (inútil)
97
+ getInfo(): string // Retorna string (ambiguo)
98
+ }`)
99
+
100
+ console.log("\n📉 Resultado:")
101
+ console.log("No es una interfaz, es una colección caótica de operaciones")
102
+ console.log("sin relación ni coherencia entre sí.")
103
+
104
+ await this.waitForEnter("\nPresiona Enter para ver cómo debe ser...")
105
+ }
106
+
107
+ async step2_CompleteInterface() {
108
+ console.clear()
109
+ console.log("✅ INTERFAZ COMPLETA Y COHERENTE")
110
+ console.log("=" .repeat(40))
111
+ console.log("Veamos una interfaz bien diseñada:")
112
+
113
+ console.log("\n🎵 CONJUNTO COMPLETO de firmas de operación:")
114
+ console.log(`interface MusicPlayerInterface {
115
+ // 🎮 GRUPO: Control de reproducción
116
+ play(songId: string): Promise<{success: boolean, message: string}>
117
+ pause(): Promise<{success: boolean, currentPosition: number}>
118
+ stop(): Promise<{success: boolean}>
119
+ resume(): Promise<{success: boolean, message: string}>
120
+
121
+ // 🔊 GRUPO: Control de audio
122
+ setVolume(level: number): {success: boolean, currentVolume: number} // 0-100
123
+ getVolume(): number
124
+ mute(): {success: boolean, previousVolume: number}
125
+ unmute(): {success: boolean, restoredVolume: number}
126
+
127
+ // 📋 GRUPO: Gestión de playlist
128
+ addSong(song: Song): {success: boolean, playlistLength: number}
129
+ removeSong(songId: string): {success: boolean, wasPlaying: boolean}
130
+ getPlaylist(): Song[]
131
+ shufflePlaylist(): {success: boolean, newOrder: string[]}
132
+
133
+ // 📊 GRUPO: Información de estado
134
+ getCurrentSong(): Song | null
135
+ getPlaybackStatus(): {
136
+ isPlaying: boolean,
137
+ isPaused: boolean,
138
+ currentTime: number,
139
+ totalTime: number,
140
+ volume: number
141
+ }
142
+ getDuration(songId: string): number | null
143
+
144
+ // ⚙️ GRUPO: Configuración
145
+ setRepeatMode(mode: 'none' | 'one' | 'all'): boolean
146
+ getRepeatMode(): 'none' | 'one' | 'all'
147
+ setShuffleMode(enabled: boolean): boolean
148
+ isShuffleEnabled(): boolean
149
+ }`)
150
+
151
+ await this.waitForEnter("\nPresiona Enter para analizar esta interfaz...")
152
+
153
+ console.log("\n🔍 ANÁLISIS del conjunto:")
154
+ console.log("\n1️⃣ COMPLETITUD:")
155
+ console.log(" • Todas las operaciones necesarias están presentes")
156
+ console.log(" • No hay funcionalidad faltante básica")
157
+ console.log(" • Cubre todo el comportamiento esperado")
158
+
159
+ console.log("\n2️⃣ COHERENCIA:")
160
+ console.log(" • Todas las firmas usan tipos consistentes")
161
+ console.log(" • Patrones de retorno consistentes")
162
+ console.log(" • Nomenclatura uniforme")
163
+
164
+ console.log("\n3️⃣ ORGANIZACIÓN:")
165
+ console.log(" • Operaciones agrupadas por funcionalidad")
166
+ console.log(" • Cada grupo tiene propósito claro")
167
+ console.log(" • Fácil de entender y recordar")
168
+
169
+ await this.waitForEnter("\nPresiona Enter para ver la implementación...")
170
+ }
171
+
172
+ async step3_InterfaceCoherence() {
173
+ console.clear()
174
+ console.log("🧩 COHERENCIA DE LA INTERFAZ")
175
+ console.log("=" .repeat(35))
176
+ console.log("Veamos cómo las firmas forman un conjunto coherente:")
177
+
178
+ console.log("\n📏 CONSISTENCIA EN TIPOS:")
179
+ console.log(`// ✅ Todas las operaciones de canciones usan string
180
+ play(songId: string)
181
+ removeSong(songId: string)
182
+ getDuration(songId: string)
183
+
184
+ // ✅ Todas las operaciones de volumen usan number (0-100)
185
+ setVolume(level: number) // 0-100
186
+ getVolume(): number // 0-100
187
+ mute(): {previousVolume: number} // 0-100`)
188
+
189
+ console.log("\n🔄 CONSISTENCIA EN PATRONES:")
190
+ console.log(`// ✅ Operaciones de configuración siguen patrón set/get
191
+ setRepeatMode(mode) / getRepeatMode()
192
+ setShuffleMode(enabled) / isShuffleEnabled()
193
+ setVolume(level) / getVolume()
194
+
195
+ // ✅ Operaciones de estado siguen patrón de objeto estructurado
196
+ getPlaybackStatus(): {isPlaying, isPaused, currentTime, ...}
197
+ pause(): {success, currentPosition}
198
+ mute(): {success, previousVolume}`)
199
+
200
+ console.log("\n🎯 COMPLETITUD FUNCIONAL:")
201
+ console.log(`// ✅ Para cada acción, hay su contraparte
202
+ play() ↔ pause() ↔ stop() ↔ resume()
203
+ mute() ↔ unmute()
204
+ addSong() ↔ removeSong()
205
+
206
+ // ✅ Para cada operación de cambio, hay consulta
207
+ setVolume() → getVolume()
208
+ setRepeatMode() → getRepeatMode()`)
209
+
210
+ await this.waitForEnter("\nPresiona Enter para ver cómo se usa...")
211
+ }
212
+
213
+ async step4_InterfaceUsage() {
214
+ console.clear()
215
+ console.log("🎭 DEMOSTRACIÓN: Uso de Interfaz Completa")
216
+ console.log("=" .repeat(45))
217
+ console.log("Veamos cómo se usa una interfaz bien diseñada:")
218
+
219
+ console.log("\n// Crear reproductor")
220
+ console.log("const player = new MusicPlayer()")
221
+ console.log("")
222
+ console.log("// 🎵 Usar GRUPO de reproducción")
223
+ console.log("const song = new Song('123', 'Bohemian Rhapsody', 'Queen')")
224
+ console.log("await player.addSong(song)")
225
+ console.log("")
226
+ console.log("const playResult = await player.play('123')")
227
+ console.log("if (playResult.success) {")
228
+ console.log(" console.log('Reproduciendo:', playResult.message)")
229
+ console.log("}")
230
+
231
+ await this.waitForEnter("\nPresiona Enter para ver más uso...")
232
+
233
+ console.log("\n// 🔊 Usar GRUPO de audio")
234
+ console.log("const volumeResult = player.setVolume(75)")
235
+ console.log("console.log('Volumen actual:', volumeResult.currentVolume)")
236
+ console.log("")
237
+ console.log("// 📊 Usar GRUPO de información")
238
+ console.log("const status = player.getPlaybackStatus()")
239
+ console.log("console.log(`Reproduciendo: ${status.isPlaying}`)")
240
+ console.log("console.log(`Tiempo: ${status.currentTime}/${status.totalTime}`)")
241
+ console.log("console.log(`Volumen: ${status.volume}`)")
242
+
243
+ await this.waitForEnter("\nPresiona Enter para ver uso avanzado...")
244
+
245
+ console.log("\n// 🎮 Combinando múltiples grupos")
246
+ console.log("async function createMusicSession() {")
247
+ console.log(" // Configurar reproductor")
248
+ console.log(" player.setRepeatMode('all')")
249
+ console.log(" player.setShuffleMode(true)")
250
+ console.log(" player.setVolume(60)")
251
+ console.log(" ")
252
+ console.log(" // Agregar canciones")
253
+ console.log(" const songs = ['123', '456', '789']")
254
+ console.log(" for (const songId of songs) {")
255
+ console.log(" await player.addSong(getSong(songId))")
256
+ console.log(" }")
257
+ console.log(" ")
258
+ console.log(" // Iniciar reproducción")
259
+ console.log(" await player.play(songs[0])")
260
+ console.log(" ")
261
+ console.log(" // Monitorear estado cada segundo")
262
+ console.log(" setInterval(() => {")
263
+ console.log(" const status = player.getPlaybackStatus()")
264
+ console.log(" updateUI(status)")
265
+ console.log(" }, 1000)")
266
+ console.log("}")
267
+
268
+ console.log("\n🌟 Beneficios observados:")
269
+ console.log("• Cada operación se complementa con las demás")
270
+ console.log("• Podemos crear flujos complejos combinando firmas")
271
+ console.log("• La interfaz completa permite cualquier funcionalidad")
272
+ console.log("• El conjunto es mayor que la suma de sus partes")
273
+
274
+ await this.waitForEnter("\nPresiona Enter para la conclusión...")
275
+ }
276
+
277
+ async conclusion() {
278
+ console.clear()
279
+ console.log("🎓 CONCLUSIÓN: Interfaz como Conjunto de Firmas")
280
+ console.log("=" .repeat(50))
281
+ console.log("🎯 Hemos demostrado que:")
282
+
283
+ console.log("\n1️⃣ Una interfaz es el CONJUNTO COMPLETO de firmas")
284
+ console.log("2️⃣ No es una operación individual, sino TODAS juntas")
285
+ console.log("3️⃣ Las firmas deben ser coherentes entre sí")
286
+ console.log("4️⃣ El conjunto debe cubrir toda la funcionalidad necesaria")
287
+
288
+ console.log("\n🧩 Características de una buena interfaz:")
289
+ console.log("• COMPLETITUD - todas las operaciones necesarias")
290
+ console.log("• COHERENCIA - tipos y patrones consistentes")
291
+ console.log("• ORGANIZACIÓN - agrupación lógica de funcionalidades")
292
+ console.log("• PREDICTIBILIDAD - comportamiento uniforme")
293
+
294
+ console.log("\n🎯 La interfaz como contrato:")
295
+ console.log("• Define TODO lo que el objeto puede hacer")
296
+ console.log("• Especifica exactamente cómo interactuar")
297
+ console.log("• Garantiza comportamiento predecible")
298
+ console.log("• Permite colaboración confiable")
299
+
300
+ console.log("\n📚 Conexión con otras lecciones:")
301
+ console.log("• Lección 1-3: Los objetos necesitan interfaces para interactuar")
302
+ console.log("• Lección 4: Cada operación de la interfaz tiene firma completa")
303
+ console.log("• Lección 5: ✅ La interfaz es el conjunto de TODAS las firmas")
304
+ console.log("• Lección 6: El énfasis debe estar en diseñar este conjunto")
305
+
306
+ console.log("\n💭 Reflexión:")
307
+ console.log("Imagina un control remoto que solo tuviera algunos botones:")
308
+ console.log("play pero no pause, volumen+ pero no volumen-. ¡Sería inútil!")
309
+ console.log("Las interfaces necesitan ser conjuntos completos y coherentes.")
310
+
311
+ console.log("\n🏆 Ahora entiendes qué es realmente una interfaz:")
312
+ console.log("el conjunto completo de todas las firmas de operación.")
313
+
314
+ await this.waitForEnter("\n✨ ¡Lección 5 completada! Presiona Enter para salir...")
315
+ }
316
+
317
+ async waitForEnter(message) {
318
+ return new Promise((resolve) => {
319
+ this.rl.question(message, () => {
320
+ resolve()
321
+ })
322
+ })
323
+ }
324
+ }
325
+
326
+ // Para usar la lección independientemente
327
+ if (import.meta.url === `file://${process.argv[1]}`) {
328
+ const lesson = new Lesson5InterfaceSet()
329
+ await lesson.start()
330
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@icarusmx/creta",
3
- "version": "0.11.0",
3
+ "version": "1.0.0",
4
4
  "description": "Salgamos de este laberinto.",
5
5
  "type": "module",
6
6
  "bin": {