@icarusmx/creta 0.8.2 → 0.9.1
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 +50 -13
- package/lessons/lesson6-interface-design.js +375 -0
- package/package.json +1 -1
package/bin/creta.js
CHANGED
|
@@ -6,6 +6,7 @@ import fs from 'fs'
|
|
|
6
6
|
import path from 'path'
|
|
7
7
|
import { fileURLToPath } from 'url'
|
|
8
8
|
import { CretaCodeSession } from '../lib/session.js'
|
|
9
|
+
import { Lesson6InterfaceDesign } from '../lessons/lesson6-interface-design.js'
|
|
9
10
|
|
|
10
11
|
const ENUNCIADOS = [
|
|
11
12
|
{
|
|
@@ -786,7 +787,7 @@ async function startEnunciadosSelectorInteractive() {
|
|
|
786
787
|
return new Promise((resolve) => {
|
|
787
788
|
renderOptions()
|
|
788
789
|
|
|
789
|
-
const onKeyPress = (key) => {
|
|
790
|
+
const onKeyPress = async (key) => {
|
|
790
791
|
if (key === 'q' || key === '\x03') { // q or Ctrl+C
|
|
791
792
|
process.stdin.setRawMode(false)
|
|
792
793
|
process.stdin.removeListener('data', onKeyPress)
|
|
@@ -810,13 +811,30 @@ async function startEnunciadosSelectorInteractive() {
|
|
|
810
811
|
console.log(`\n💡 Enfoque: ${enunciadoSeleccionado.enfoque}`)
|
|
811
812
|
console.log(`📚 Nivel: ${enunciadoSeleccionado.nivel}`)
|
|
812
813
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
814
|
+
// Check if we have a lesson implementation for this enunciado
|
|
815
|
+
if (enunciadoSeleccionado.id === 6) {
|
|
816
|
+
console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
|
|
817
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
818
|
+
|
|
819
|
+
try {
|
|
820
|
+
const lesson6 = new Lesson6InterfaceDesign()
|
|
821
|
+
await lesson6.start()
|
|
822
|
+
} catch (error) {
|
|
823
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
824
|
+
console.log("\n🚀 Próximamente:")
|
|
825
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
826
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
827
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
828
|
+
}
|
|
829
|
+
} else {
|
|
830
|
+
console.log("\n🚀 Próximamente:")
|
|
831
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
832
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
833
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
817
834
|
|
|
818
|
-
|
|
819
|
-
|
|
835
|
+
console.log("\n💭 Por ahora, reflexiona: ¿qué parte específica de este enunciado")
|
|
836
|
+
console.log(" te genera más curiosidad o confusión?")
|
|
837
|
+
}
|
|
820
838
|
|
|
821
839
|
resolve()
|
|
822
840
|
return
|
|
@@ -876,13 +894,32 @@ async function startEnunciadosSelectorFallback() {
|
|
|
876
894
|
console.log(`\n💡 Enfoque: ${enunciadoSeleccionado.enfoque}`)
|
|
877
895
|
console.log(`📚 Nivel: ${enunciadoSeleccionado.nivel}`)
|
|
878
896
|
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
897
|
+
// Check if we have a lesson implementation for this enunciado
|
|
898
|
+
if (enunciadoSeleccionado.id === 6) {
|
|
899
|
+
console.log("\n🚀 ¡Lección disponible! Iniciando sesión de estudio dirigida...")
|
|
900
|
+
rl.close()
|
|
901
|
+
await new Promise(resolve => setTimeout(resolve, 1500)) // Brief pause
|
|
902
|
+
|
|
903
|
+
try {
|
|
904
|
+
const lesson6 = new Lesson6InterfaceDesign()
|
|
905
|
+
await lesson6.start()
|
|
906
|
+
} catch (error) {
|
|
907
|
+
console.error("\n❌ Error al ejecutar la lección:", error.message)
|
|
908
|
+
console.log("\n🚀 Próximamente:")
|
|
909
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
910
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
911
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
912
|
+
}
|
|
913
|
+
return
|
|
914
|
+
} else {
|
|
915
|
+
console.log("\n🚀 Próximamente:")
|
|
916
|
+
console.log("- Sesiones de estudio dirigidas basadas en este enunciado")
|
|
917
|
+
console.log("- Ejercicios prácticos que ilustren el concepto")
|
|
918
|
+
console.log("- Proyectos específicos para internalizar la idea")
|
|
883
919
|
|
|
884
|
-
|
|
885
|
-
|
|
920
|
+
console.log("\n💭 Por ahora, reflexiona: ¿qué parte específica de este enunciado")
|
|
921
|
+
console.log(" te genera más curiosidad o confusión?")
|
|
922
|
+
}
|
|
886
923
|
|
|
887
924
|
} else {
|
|
888
925
|
console.log("❌ Opción no válida. Elige un número entre 1 y 6.")
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// LECCIÓN 6: El énfasis al diseñar los objetos debe estar en la definición de sus solicitudes e interfaces
|
|
4
|
+
// Enfoque práctico: Sistema bancario con diseño interface-first y encapsulación
|
|
5
|
+
|
|
6
|
+
import { createInterface } from 'readline'
|
|
7
|
+
|
|
8
|
+
export class Lesson6InterfaceDesign {
|
|
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 6: Diseño basado en Interfaces")
|
|
18
|
+
console.log("=" .repeat(50))
|
|
19
|
+
console.log("📚 Concepto: El énfasis al diseñar los objetos debe estar en la definición de sus solicitudes e interfaces.")
|
|
20
|
+
console.log("\n💡 ¿Por qué es importante?")
|
|
21
|
+
console.log("- Las interfaces definen QUÉ hace un objeto, no CÓMO lo hace")
|
|
22
|
+
console.log("- Facilita la colaboración entre objetos")
|
|
23
|
+
console.log("- Permite cambiar implementaciones sin afectar otros objetos")
|
|
24
|
+
console.log("- Hace el código más mantenible y extensible")
|
|
25
|
+
|
|
26
|
+
await this.waitForEnter("\nPresiona Enter para comenzar el ejercicio práctico...")
|
|
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: Sistema Bancario")
|
|
37
|
+
console.log("=" .repeat(50))
|
|
38
|
+
console.log("🎯 Objetivo: Diseñar interfaces ANTES de implementar")
|
|
39
|
+
console.log("\nVamos a crear un sistema bancario donde:")
|
|
40
|
+
console.log("- BankAccount representa una cuenta con balance privado")
|
|
41
|
+
console.log("- Transaction registra movimientos entre cuentas")
|
|
42
|
+
console.log("- Bank gestiona múltiples cuentas y validaciones")
|
|
43
|
+
|
|
44
|
+
await this.waitForEnter("\nPresiona Enter para ver cómo diseñar las interfaces...")
|
|
45
|
+
|
|
46
|
+
await this.step1_DefineRequests()
|
|
47
|
+
await this.step2_DefineInterfaces()
|
|
48
|
+
await this.step3_ImplementObjects()
|
|
49
|
+
await this.step4_TestInteraction()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async step1_DefineRequests() {
|
|
53
|
+
console.clear()
|
|
54
|
+
console.log("📋 PASO 1: Definir las Solicitudes")
|
|
55
|
+
console.log("=" .repeat(40))
|
|
56
|
+
console.log("Antes de escribir código, pensemos: ¿Qué solicitudes debe manejar cada objeto?")
|
|
57
|
+
console.log("\n🏦 BankAccount debe poder:")
|
|
58
|
+
console.log(" - Consultar balance (sin exponer el dato interno)")
|
|
59
|
+
console.log(" - Recibir dinero (depósito)")
|
|
60
|
+
console.log(" - Enviar dinero (con validación interna)")
|
|
61
|
+
console.log(" - Proporcionar información de la cuenta")
|
|
62
|
+
|
|
63
|
+
console.log("\n📊 Transaction debe poder:")
|
|
64
|
+
console.log(" - Registrar origen, destino y monto")
|
|
65
|
+
console.log(" - Proporcionar detalles del movimiento")
|
|
66
|
+
console.log(" - Validar si la transacción es válida")
|
|
67
|
+
|
|
68
|
+
console.log("\n🏛️ Bank debe poder:")
|
|
69
|
+
console.log(" - Crear nuevas cuentas")
|
|
70
|
+
console.log(" - Procesar transferencias entre cuentas")
|
|
71
|
+
console.log(" - Validar operaciones antes de ejecutarlas")
|
|
72
|
+
console.log(" - Llevar registro de todas las transacciones")
|
|
73
|
+
|
|
74
|
+
await this.waitForEnter("\n✅ ¡Excelente! Ya definimos QUÉ debe hacer cada objeto. Presiona Enter para definir las interfaces...")
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async step2_DefineInterfaces() {
|
|
78
|
+
console.clear()
|
|
79
|
+
console.log("🔌 PASO 2: Definir las Interfaces (Firmas de Operación)")
|
|
80
|
+
console.log("=" .repeat(50))
|
|
81
|
+
console.log("Ahora especifiquemos CÓMO se solicitan estas operaciones:")
|
|
82
|
+
|
|
83
|
+
console.log("\n// BankAccount Interface")
|
|
84
|
+
console.log("class BankAccount {")
|
|
85
|
+
console.log(" constructor(accountNumber, ownerName, initialBalance) → BankAccount")
|
|
86
|
+
console.log(" getBalance() → number // ⚠️ ENCAPSULACIÓN: acceso controlado")
|
|
87
|
+
console.log(" getAccountInfo() → {number, owner, balance}")
|
|
88
|
+
console.log(" deposit(amount) → boolean")
|
|
89
|
+
console.log(" send(amount, targetAccount) → boolean // ⚠️ VALIDACIÓN interna")
|
|
90
|
+
console.log("}")
|
|
91
|
+
|
|
92
|
+
console.log("\n// Transaction Interface")
|
|
93
|
+
console.log("class Transaction {")
|
|
94
|
+
console.log(" constructor(from, to, amount, timestamp) → Transaction")
|
|
95
|
+
console.log(" getDetails() → {from, to, amount, timestamp, status}")
|
|
96
|
+
console.log(" isValid() → boolean")
|
|
97
|
+
console.log("}")
|
|
98
|
+
|
|
99
|
+
console.log("\n// Bank Interface")
|
|
100
|
+
console.log("class Bank {")
|
|
101
|
+
console.log(" createAccount(ownerName, initialBalance) → BankAccount")
|
|
102
|
+
console.log(" transfer(fromAccount, toAccount, amount) → Transaction")
|
|
103
|
+
console.log(" getAllTransactions() → Array<Transaction>")
|
|
104
|
+
console.log(" validateOperation(account, amount) → boolean")
|
|
105
|
+
console.log("}")
|
|
106
|
+
|
|
107
|
+
console.log("\n💡 Observa que cada operación especifica:")
|
|
108
|
+
console.log(" a) Nombre de la operación (getBalance, send, transfer, etc.)")
|
|
109
|
+
console.log(" b) Insumos necesarios (amount, targetAccount, etc.)")
|
|
110
|
+
console.log(" c) Valor que regresa (boolean, Transaction, etc.)")
|
|
111
|
+
console.log("\n🔒 Nota especial: getBalance() encapsula el acceso al estado interno")
|
|
112
|
+
console.log("🛡️ Nota especial: send() incluirá validación antes de ejecutar")
|
|
113
|
+
|
|
114
|
+
await this.waitForEnter("\n✅ Interfaces definidas. Presiona Enter para implementar...")
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async step3_ImplementObjects() {
|
|
118
|
+
console.clear()
|
|
119
|
+
console.log("⚙️ PASO 3: Implementar los Objetos")
|
|
120
|
+
console.log("=" .repeat(40))
|
|
121
|
+
console.log("Ahora que tenemos las interfaces claras, implementemos:")
|
|
122
|
+
|
|
123
|
+
console.log("\n// Implementación de BankAccount")
|
|
124
|
+
console.log(`class BankAccount {
|
|
125
|
+
constructor(accountNumber, ownerName, initialBalance) {
|
|
126
|
+
this.accountNumber = accountNumber
|
|
127
|
+
this.ownerName = ownerName
|
|
128
|
+
this.#balance = initialBalance // 🔒 PRIVADO: no se accede directamente
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 🔑 ENCAPSULACIÓN: método GET para acceder al balance
|
|
132
|
+
getBalance() {
|
|
133
|
+
return this.#balance
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
getAccountInfo() {
|
|
137
|
+
return {
|
|
138
|
+
number: this.accountNumber,
|
|
139
|
+
owner: this.ownerName,
|
|
140
|
+
balance: this.#balance // Controlamos qué se expone
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
deposit(amount) {
|
|
145
|
+
if (amount > 0) {
|
|
146
|
+
this.#balance += amount
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
return false
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 🛡️ VALIDACIÓN: método SEND con lógica interna
|
|
153
|
+
send(amount, targetAccount) {
|
|
154
|
+
// Validación interna ANTES de ejecutar
|
|
155
|
+
if (amount > 0 && this.#balance >= amount) {
|
|
156
|
+
this.#balance -= amount
|
|
157
|
+
targetAccount.deposit(amount)
|
|
158
|
+
return true
|
|
159
|
+
}
|
|
160
|
+
return false // Fondos insuficientes o monto inválido
|
|
161
|
+
}
|
|
162
|
+
}`)
|
|
163
|
+
|
|
164
|
+
await this.waitForEnter("\nPresiona Enter para ver Transaction...")
|
|
165
|
+
|
|
166
|
+
console.log("\n// Implementación de Transaction")
|
|
167
|
+
console.log(`class Transaction {
|
|
168
|
+
constructor(fromAccount, toAccount, amount) {
|
|
169
|
+
this.fromAccount = fromAccount
|
|
170
|
+
this.toAccount = toAccount
|
|
171
|
+
this.amount = amount
|
|
172
|
+
this.timestamp = new Date()
|
|
173
|
+
this.status = 'pending'
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
getDetails() {
|
|
177
|
+
return {
|
|
178
|
+
from: this.fromAccount.accountNumber,
|
|
179
|
+
to: this.toAccount.accountNumber,
|
|
180
|
+
amount: this.amount,
|
|
181
|
+
timestamp: this.timestamp,
|
|
182
|
+
status: this.status
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
isValid() {
|
|
187
|
+
return this.amount > 0 &&
|
|
188
|
+
this.fromAccount.getBalance() >= this.amount
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
execute() {
|
|
192
|
+
if (this.isValid()) {
|
|
193
|
+
const success = this.fromAccount.send(this.amount, this.toAccount)
|
|
194
|
+
this.status = success ? 'completed' : 'failed'
|
|
195
|
+
return success
|
|
196
|
+
}
|
|
197
|
+
this.status = 'failed'
|
|
198
|
+
return false
|
|
199
|
+
}
|
|
200
|
+
}`)
|
|
201
|
+
|
|
202
|
+
await this.waitForEnter("\nPresiona Enter para ver Bank...")
|
|
203
|
+
|
|
204
|
+
console.log("\n// Implementación de Bank")
|
|
205
|
+
console.log(`class Bank {
|
|
206
|
+
constructor() {
|
|
207
|
+
this.accounts = []
|
|
208
|
+
this.transactions = []
|
|
209
|
+
this.nextAccountNumber = 1000
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
createAccount(ownerName, initialBalance) {
|
|
213
|
+
const account = new BankAccount(
|
|
214
|
+
this.nextAccountNumber++,
|
|
215
|
+
ownerName,
|
|
216
|
+
initialBalance
|
|
217
|
+
)
|
|
218
|
+
this.accounts.push(account)
|
|
219
|
+
return account
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
transfer(fromAccount, toAccount, amount) {
|
|
223
|
+
const transaction = new Transaction(fromAccount, toAccount, amount)
|
|
224
|
+
|
|
225
|
+
// El Bank valida ANTES de ejecutar
|
|
226
|
+
if (this.validateOperation(fromAccount, amount)) {
|
|
227
|
+
const success = transaction.execute()
|
|
228
|
+
this.transactions.push(transaction)
|
|
229
|
+
return transaction
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
transaction.status = 'failed'
|
|
233
|
+
this.transactions.push(transaction)
|
|
234
|
+
return transaction
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
validateOperation(account, amount) {
|
|
238
|
+
return amount > 0 && account.getBalance() >= amount
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
getAllTransactions() {
|
|
242
|
+
return [...this.transactions]
|
|
243
|
+
}
|
|
244
|
+
}`)
|
|
245
|
+
|
|
246
|
+
await this.waitForEnter("\n✅ Implementación completa. Presiona Enter para probar la interacción...")
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async step4_TestInteraction() {
|
|
250
|
+
console.clear()
|
|
251
|
+
console.log("🧪 PASO 4: Probar la Interacción entre Objetos")
|
|
252
|
+
console.log("=" .repeat(45))
|
|
253
|
+
console.log("Veamos cómo los objetos colaboran usando sus interfaces:")
|
|
254
|
+
|
|
255
|
+
console.log("\n// Crear el sistema bancario")
|
|
256
|
+
console.log("const bank = new Bank()")
|
|
257
|
+
console.log("const cuenta1 = bank.createAccount('Ana García', 1000)")
|
|
258
|
+
console.log("const cuenta2 = bank.createAccount('Carlos López', 500)")
|
|
259
|
+
console.log("")
|
|
260
|
+
console.log("// 🔑 ENCAPSULACIÓN: Solo podemos acceder al balance via getBalance()")
|
|
261
|
+
console.log("console.log('Balance Ana:', cuenta1.getBalance()) // 1000")
|
|
262
|
+
console.log("console.log('Balance Carlos:', cuenta2.getBalance()) // 500")
|
|
263
|
+
console.log("")
|
|
264
|
+
console.log("// 🛡️ VALIDACIÓN: send() verifica internamente antes de ejecutar")
|
|
265
|
+
console.log("const exitoso = cuenta1.send(300, cuenta2) // ✅ Tiene fondos")
|
|
266
|
+
console.log("console.log('Transferencia exitosa:', exitoso) // true")
|
|
267
|
+
console.log("")
|
|
268
|
+
console.log("const fallido = cuenta1.send(1500, cuenta2) // ❌ Fondos insuficientes")
|
|
269
|
+
console.log("console.log('Transferencia fallida:', fallido) // false")
|
|
270
|
+
console.log("")
|
|
271
|
+
console.log("// El estado interno se mantiene íntegro")
|
|
272
|
+
console.log("console.log('Balance final Ana:', cuenta1.getBalance()) // 700")
|
|
273
|
+
console.log("console.log('Balance final Carlos:', cuenta2.getBalance()) // 800")
|
|
274
|
+
|
|
275
|
+
console.log("\n🎯 Resultado esperado:")
|
|
276
|
+
console.log("Balance Ana: 1000")
|
|
277
|
+
console.log("Balance Carlos: 500")
|
|
278
|
+
console.log("Transferencia exitosa: true")
|
|
279
|
+
console.log("Transferencia fallida: false")
|
|
280
|
+
console.log("Balance final Ana: 700")
|
|
281
|
+
console.log("Balance final Carlos: 800")
|
|
282
|
+
|
|
283
|
+
await this.waitForEnter("\nPresiona Enter para ver los beneficios de este enfoque...")
|
|
284
|
+
|
|
285
|
+
console.clear()
|
|
286
|
+
console.log("🌟 BENEFICIOS DEL DISEÑO INTERFACE-FIRST EN SISTEMAS BANCARIOS")
|
|
287
|
+
console.log("=" .repeat(60))
|
|
288
|
+
console.log("1. 🔒 Encapsulación: El balance está protegido, solo accesible via getBalance()")
|
|
289
|
+
console.log("2. 🛡️ Validación: send() incluye lógica de negocio interna")
|
|
290
|
+
console.log("3. 🎯 Claridad: Cada objeto tiene responsabilidades financieras bien definidas")
|
|
291
|
+
console.log("4. 🔗 Colaboración: Los objetos saben exactamente cómo solicitar operaciones")
|
|
292
|
+
console.log("5. 🧪 Testeable: Podemos simular cuentas y transacciones fácilmente")
|
|
293
|
+
console.log("6. 📚 Mantenible: Las interfaces documentan el contrato bancario")
|
|
294
|
+
|
|
295
|
+
console.log("\n💡 Ejemplo de extensibilidad:")
|
|
296
|
+
console.log("// Podemos crear diferentes tipos de cuenta sin cambiar Bank")
|
|
297
|
+
console.log("class SavingsAccount extends BankAccount {")
|
|
298
|
+
console.log(" getBalance() {")
|
|
299
|
+
console.log(" return super.getBalance() + this.calculateInterest()")
|
|
300
|
+
console.log(" }")
|
|
301
|
+
console.log("}")
|
|
302
|
+
console.log("")
|
|
303
|
+
console.log("class CreditAccount extends BankAccount {")
|
|
304
|
+
console.log(" send(amount, target) {")
|
|
305
|
+
console.log(" // Permite sobregiro hasta el límite de crédito")
|
|
306
|
+
console.log(" if (amount > 0 && (this.getBalance() + this.creditLimit) >= amount) {")
|
|
307
|
+
console.log(" // ... lógica específica")
|
|
308
|
+
console.log(" }")
|
|
309
|
+
console.log(" }")
|
|
310
|
+
console.log("}")
|
|
311
|
+
console.log("")
|
|
312
|
+
console.log("// Bank sigue funcionando igual con cualquier tipo de cuenta!")
|
|
313
|
+
console.log("const savingsAcc = new SavingsAccount(123, 'María', 1000)")
|
|
314
|
+
console.log("const creditAcc = new CreditAccount(456, 'Juan', 500, 2000) // límite crédito")
|
|
315
|
+
console.log("bank.transfer(savingsAcc, creditAcc, 300) // ¡Funciona!")
|
|
316
|
+
|
|
317
|
+
await this.waitForEnter("\nPresiona Enter para continuar con la conclusión...")
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async conclusion() {
|
|
321
|
+
console.clear()
|
|
322
|
+
console.log("🎓 CONCLUSIÓN: Diseño basado en Interfaces (Sistema Bancario)")
|
|
323
|
+
console.log("=" .repeat(55))
|
|
324
|
+
console.log("🎯 Hemos demostrado que:")
|
|
325
|
+
console.log("\n1. El ÉNFASIS debe estar en definir QUÉ solicitudes maneja cada objeto")
|
|
326
|
+
console.log("2. Las INTERFACES especifican cómo hacer estas solicitudes")
|
|
327
|
+
console.log("3. La IMPLEMENTACIÓN viene después, siguiendo el contrato")
|
|
328
|
+
console.log("4. Los objetos COLABORAN a través de estas interfaces bien definidas")
|
|
329
|
+
|
|
330
|
+
console.log("\n🔑 Lecciones específicas del ejemplo bancario:")
|
|
331
|
+
console.log("• ENCAPSULACIÓN: getBalance() protege el acceso al estado interno")
|
|
332
|
+
console.log("• VALIDACIÓN: send() ejecuta lógica de negocio antes de operar")
|
|
333
|
+
console.log("• RESPONSABILIDAD: Cada objeto maneja su propia integridad")
|
|
334
|
+
console.log("• COLABORACIÓN: Bank, BankAccount y Transaction trabajan juntos")
|
|
335
|
+
|
|
336
|
+
console.log("\n📚 Conexión con lecciones anteriores:")
|
|
337
|
+
console.log("• Lección 2: Los objetos interactúan a través de solicitudes ✓")
|
|
338
|
+
console.log("• Lección 3: Las solicitudes son la única forma de ejecutar operaciones ✓")
|
|
339
|
+
console.log("• Lección 4: Cada operación tiene nombre, insumos y valor de retorno ✓")
|
|
340
|
+
console.log("• Lección 5: La interfaz es el conjunto de todas las firmas ✓")
|
|
341
|
+
console.log("• Lección 6: El énfasis está en definir solicitudes e interfaces ✓")
|
|
342
|
+
|
|
343
|
+
console.log("\n🚀 Próximo paso:")
|
|
344
|
+
console.log("Practica este enfoque en tus propios proyectos:")
|
|
345
|
+
console.log("1. Define primero QUÉ debe hacer cada objeto")
|
|
346
|
+
console.log("2. Especifica las interfaces (firmas de operación)")
|
|
347
|
+
console.log("3. Incluye validaciones internas en tus métodos")
|
|
348
|
+
console.log("4. Encapsula el estado, expón solo lo necesario")
|
|
349
|
+
console.log("5. Haz que los objetos colaboren a través de solicitudes")
|
|
350
|
+
|
|
351
|
+
console.log("\n💭 Reflexión final:")
|
|
352
|
+
console.log("En el mundo real, ¿cómo te asegurarías de que tu cuenta bancaria")
|
|
353
|
+
console.log("esté protegida y que solo se ejecuten operaciones válidas?")
|
|
354
|
+
console.log("¡Exactamente como lo hicimos aquí: interfaces bien definidas!")
|
|
355
|
+
|
|
356
|
+
console.log("\n🏆 ¡Has completado el ejemplo más importante del diseño orientado a objetos!")
|
|
357
|
+
console.log("Ahora entiendes por qué el ÉNFASIS debe estar en las interfaces.")
|
|
358
|
+
|
|
359
|
+
await this.waitForEnter("\n✨ ¡Lección 6 completada! Presiona Enter para salir...")
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async waitForEnter(message) {
|
|
363
|
+
return new Promise((resolve) => {
|
|
364
|
+
this.rl.question(message, () => {
|
|
365
|
+
resolve()
|
|
366
|
+
})
|
|
367
|
+
})
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Para usar la lección independientemente
|
|
372
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
373
|
+
const lesson = new Lesson6InterfaceDesign()
|
|
374
|
+
await lesson.start()
|
|
375
|
+
}
|