From 239ce12c348ba2d52aad1d540a60559a9057e062 Mon Sep 17 00:00:00 2001 From: jpconsuegra Date: Sat, 4 May 2024 09:53:34 -0400 Subject: [PATCH] Add Lecture 12 (+Code) --- .../12-inheritance/code/cuentas/Cuenta.cs | 136 ++++++++++++++++++ .../12-inheritance/code/cuentas/Program.cs | 105 ++++++++++++++ .../12-inheritance/code/cuentas/Tienda.cs | 42 ++++++ .../code/cuentas/cuentas.csproj | 10 ++ conferences/2024/12-inheritance/lecture-12.md | 61 ++++++++ 5 files changed, 354 insertions(+) create mode 100644 conferences/2024/12-inheritance/code/cuentas/Cuenta.cs create mode 100644 conferences/2024/12-inheritance/code/cuentas/Program.cs create mode 100644 conferences/2024/12-inheritance/code/cuentas/Tienda.cs create mode 100644 conferences/2024/12-inheritance/code/cuentas/cuentas.csproj create mode 100644 conferences/2024/12-inheritance/lecture-12.md diff --git a/conferences/2024/12-inheritance/code/cuentas/Cuenta.cs b/conferences/2024/12-inheritance/code/cuentas/Cuenta.cs new file mode 100644 index 0000000..770ca51 --- /dev/null +++ b/conferences/2024/12-inheritance/code/cuentas/Cuenta.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace WEBOO.Programacion +{ + public class Cuenta + { + public string Titular { get; private set; } + public float Saldo { get; protected set; } + + public Cuenta(string titular, float saldoInicial) + { + Titular = titular; + if (saldoInicial < 0) + throw new Exception("Hay que abrir una cuenta con saldo mayor que 0"); + Saldo = saldoInicial; + } + + public void Deposita(float cantidad) + { + if (cantidad <= 0) + throw new Exception("Cantidad a depositar debe ser mayor que cero"); + Saldo += cantidad; + } + + public void Extrae(float cantidad) + { + if (cantidad <= 0) + throw new Exception("Cantidad a extraer debe ser mayor que cero"); + else if (Saldo - cantidad < 0) + throw new Exception("No hay saldo para extraer"); + Saldo -= cantidad; + } + + + } + + #region CUENTA CON TRANSFERENCIA SIN USAR HERENCIA + //Se repite código fuente + public class CuentaTransferenciaCopiando + { + public string Titular { get; private set; } + public float Saldo { get; private set; } + + public CuentaTransferenciaCopiando(string titular, float saldoInicial) + { + Titular = titular; + if (saldoInicial < 0) + throw new Exception("Hay que abrir una cuenta con saldo mayor que 0"); + Saldo = saldoInicial; + } + + public void Deposita(float cantidad) + { + if (cantidad <= 0) + throw new Exception("Cantidad a depositar debe ser mayor que cero"); + Saldo += cantidad; + } + + public void Extrae(float cantidad) + { + if (cantidad <= 0) + throw new Exception("Cantidad a extraer debe ser mayor que cero"); + else if (Saldo - cantidad < 0) + throw new Exception("No hay saldo para extraer"); + Saldo -= cantidad; + } + + public void Transfiere(float cantidad, Cuenta otraCuenta) + { + if (cantidad <= 0) + throw new Exception("Cantidad a transferir debe ser mayor que cero"); + else if (Saldo >= cantidad) + { + otraCuenta.Deposita(cantidad); + Extrae(cantidad); + } + else + throw new Exception("No hay saldo suficiente para hacer el traspaso"); + } + + + } + #endregion + + #region CUENTA CON TRANSFERENCIA USANDO HERENCIA + public class CuentaTransferencia : Cuenta + { + + public CuentaTransferencia(string titular, float saldoInicial) : base(titular, saldoInicial) + { } + + public void Transfiere(float cantidad, Cuenta otraCuenta) + { + if (cantidad <= 0) + throw new Exception("Cantidad a transferir debe ser mayor que cero"); + else if (Saldo >= cantidad) + { + otraCuenta.Deposita(cantidad); + Extrae(cantidad); + } + else + throw new Exception("No hay saldo suficiente para hacer el traspaso"); + } + + } + #endregion + + #region CREDITO CON HERENCIA + //Para probar principio de sustitución añadir override en la redefinición de Extrae + public class CuentaCredito : Cuenta + { + public float Interes { get; private set; } + + public CuentaCredito(string titular, float saldoInicial, float tasaInteres = 5) : base(titular, saldoInicial) + { + if (tasaInteres > 0 && tasaInteres < 100) + Interes = tasaInteres; + else throw new Exception("Tasa interés incorrecta"); + } + + public void Extrae(float cantidad) + { + if (cantidad <= 0) + throw new Exception("Cantidad a extraer debe ser mayor que cero"); + else if (Saldo >= cantidad) + Saldo -= cantidad; + else // No hay saldo suficiente se va extraer a crédito con X% de interés + Saldo -= (cantidad + (cantidad * Interes / 100)); + } + } + #endregion + +} \ No newline at end of file diff --git a/conferences/2024/12-inheritance/code/cuentas/Program.cs b/conferences/2024/12-inheritance/code/cuentas/Program.cs new file mode 100644 index 0000000..68573fc --- /dev/null +++ b/conferences/2024/12-inheritance/code/cuentas/Program.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Text; + + +namespace WEBOO.Programacion +{ + class Program + { + + //Probar Herencia con ampliación, clases Cuenta y Cuenta con Transferencia + static void ProbarCuentaConTransferencia() + { + Console.WriteLine("Prueba de Herencia en Código Fuente..."); + Console.WriteLine("Crea cuenta Juan con saldo inicial de 500"); + Cuenta cuentaJuan = new Cuenta("Juan", 500); + Console.WriteLine("{0} tiene un saldo de {1}", cuentaJuan.Titular, cuentaJuan.Saldo); + + Console.WriteLine("\nEntra cantidad a depositar en la cuenta de Juan"); + int cantidad = int.Parse(Console.ReadLine()); + cuentaJuan.Deposita(cantidad); + Console.WriteLine("{0} tiene un saldo de {1}", cuentaJuan.Titular, cuentaJuan.Saldo); + + Console.WriteLine("\nEntra cantidad a extraer de la cuenta de Juan (prueba también con una cantidad imposible)"); + cantidad = int.Parse(Console.ReadLine()); + cuentaJuan.Extrae(cantidad); + Console.WriteLine("{0} tiene un saldo de {1}", cuentaJuan.Titular, cuentaJuan.Saldo); + + // Descomentar para ver error de compilación porque Cuenta no tiene transfiere + // cuentaJuan.Transfiere(200); + + CuentaTransferencia cuentaLuis = new CuentaTransferencia("Luis", 100); + Console.WriteLine("\n{0} tiene un saldo de {1}", cuentaLuis.Titular, cuentaLuis.Saldo); + Console.WriteLine("Deposita 100"); + cuentaLuis.Deposita(100); + Console.WriteLine("Extrae 20"); + cuentaLuis.Extrae(20); + Console.WriteLine("\n{0} tiene un saldo de {1}", cuentaLuis.Titular, cuentaLuis.Saldo); + + Console.WriteLine("\nEntra cantidad a transferir de Luis a Juan"); + cantidad = int.Parse(Console.ReadLine()); + Console.WriteLine("...transferir {0} de {1} a {2}", cantidad, cuentaLuis.Titular, cuentaJuan.Titular); + cuentaLuis.Transfiere(cantidad, cuentaJuan); + Console.WriteLine("\n{0} tiene un saldo de {1}", cuentaJuan.Titular, cuentaJuan.Saldo); + Console.WriteLine("\n{0} tiene un saldo de {1}", cuentaLuis.Titular, cuentaLuis.Saldo); + Console.ReadLine(); + } + + //Para probar cambiar Cuenta por CuentaCredito + static void ProbarCuentaDeCrédito() + { + Cuenta juan = new Cuenta("Juan", 1000); + Console.WriteLine("{0} tiene un saldo de {1}", juan.Titular, juan.Saldo); + Tienda t = new Tienda(); + Producto tv = new Producto("TV Sony", 500); + Producto tableta = new Producto("Tableta Samsung", 300); + Producto refri = new Producto("Refrigerador LG", 700); + + Console.WriteLine("\nTienda vende TV a Juan"); + t.Vende(tv, juan); + Console.WriteLine("{0} tiene un saldo de {1}", juan.Titular, juan.Saldo); + + //Si se descomenta lo siguiente da excepción porque Juan no tiene saldo + //Console.WriteLine("\nVeamos si Juan sin saldo puede comprar"); + //Console.ReadLine(); + //Console.WriteLine("Tienda vende Refrigerador a Juan"); + //t.Vende(refri, juan); + //Console.WriteLine("{0} tiene un saldo de {1}", juan.Titular, juan.Saldo); + + CuentaCredito mk = new CuentaCredito("Miguel", 1000); + TiendaCredito tc = new TiendaCredito(); + Console.WriteLine("{0} tiene un saldo de {1}", mk.Titular, mk.Saldo); + + Console.WriteLine("\nMiguel va a comprar TV en Tienda de Credito"); + tc.Vende(tv, mk); + Console.WriteLine("{0} tiene un saldo de {1}", mk.Titular, mk.Saldo); + + Console.WriteLine("\nMiguel va a comprar Refrigerador en Tienda de Crédito"); + tc.Vende(refri, mk); + Console.WriteLine("{0} tiene un saldo de {1}", mk.Titular, mk.Saldo); + + //Debe dar excepción lo siguiente, eso está bien que ocurra de esa manera + // Console.WriteLine("\nMiguel va a comprar Tableta en Tienda normal"); + // Console.ReadLine(); + // t.Vende(tableta, mk); + + //Pero tampoco alguien aunque tenga saldo puede comprar en la tienda de crédito + //Error de compilación si se descomenta + //tc.Vende(tableta, juan); + + //Este no da error de compilación y puede comprar + Console.WriteLine("\nJuan va a comprar Tableta en Tienda normal"); + t.Vende(tableta, juan); + Console.WriteLine("{0} tiene un saldo de {1}", juan.Titular, juan.Saldo); + } + + + static void Main(string[] args) + { + ProbarCuentaConTransferencia(); + Console.WriteLine("-------------------"); + ProbarCuentaDeCrédito(); + } + } +} diff --git a/conferences/2024/12-inheritance/code/cuentas/Tienda.cs b/conferences/2024/12-inheritance/code/cuentas/Tienda.cs new file mode 100644 index 0000000..b48d043 --- /dev/null +++ b/conferences/2024/12-inheritance/code/cuentas/Tienda.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace WEBOO.Programacion +{ + class Producto + { + public string Nombre { get; private set; } + public float Precio { get; private set; } + public Producto(string nombre, float precio) + { + Nombre = nombre; Precio = precio; + } + } + class Tienda + { + public void Vende(Producto item, Cuenta cliente) + { + cliente.Extrae(item.Precio); + Console.WriteLine( + "Tienda vende {0} de precio {1} a {2}", + item.Nombre, + item.Precio, + cliente.Titular + ); + } + } + class TiendaCredito + { + public void Vende(Producto item, CuentaCredito cliente) + { + cliente.Extrae(item.Precio); + Console.WriteLine( + "Tienda de Crédito vende {0} de precio {1} a {2}", + item.Nombre, + item.Precio, + cliente.Titular + ); + } + } +} diff --git a/conferences/2024/12-inheritance/code/cuentas/cuentas.csproj b/conferences/2024/12-inheritance/code/cuentas/cuentas.csproj new file mode 100644 index 0000000..d439800 --- /dev/null +++ b/conferences/2024/12-inheritance/code/cuentas/cuentas.csproj @@ -0,0 +1,10 @@ + + + + Exe + net7.0 + enable + enable + + + diff --git a/conferences/2024/12-inheritance/lecture-12.md b/conferences/2024/12-inheritance/lecture-12.md new file mode 100644 index 0000000..255d194 --- /dev/null +++ b/conferences/2024/12-inheritance/lecture-12.md @@ -0,0 +1,61 @@ +# Herencia + +Desde las primeras clases del curso se ha hecho énfasis en la importancia de reutilizar código: +- Código más corto, conciso y legible. +- Detección de errores: las instrucciones se localizan en un solo lugar. +- Consistencia del programa: tras actualizar no hay réplicas que modificar. + +¿Con qué recursos de programación contamos para reutilizar código? +- Métodos (para reutilizar instrucciones comunes a funciones distintas). +- Herencia de clases (para reutilizar funcionalidades comunes a distintos tipos). + + - Por ejemplo, podemos querer modelar el personal involucrado en una institución (los estudiantes, profesores y administrativos de la facultad). + Sabemos que todos son personas y por tanto hay características comunes que vamos a querer almacenar de todos (nombre, fecha de nacimiento, años vinculados a la facultad, etc.). + Por otro lado, de los estudiantes podríamos querer almacenar adicionalmente el año académico en el que se encuentran y de los profesores y administrativos la fecha de contratación. + Además, algunas funcionalidades pueden ser comunes a todas las personas (por ejemplo, una función que incremente en 1 los años que lleva una persona vinculada con la facultad) mientras que otras pueden ser exclusivas de los estudiantes (por ejemplo, una función que lo promueve al siguiente año académico). + + - Otro ejemplo sería querer modelar un sistema de cuentas bancarias. + Pueden haber cuentas básicas con las funcionalidades mínimas, pero pueden haber cuentas con servicios premium como puede ser pago por crédito en lugar de solo débito. + > Ver ejemplos de código en la carpeta `code`. + +## Tipo de herencia + +La herencia se puede aplicar con distintos propósitos. + +- Para **ampliar**: añadir nuevas funcionalidades al tipo (hacer lo mismo y **más**). +- Para **especializar**: cambiar alguna de sus funcionalidades (hacer lo mismo, pero **mejor**, más especializado). + +> **OJO:** el mayor atractivo de la herencia no es la reutilización de código!!! De hecho, muchas veces se puede hacer un uso indevido de la herencia con dicho propósito. +> > **Ejemplo:** clase `Person` hereda de `Math` para "saber" hacer Pow, Min, ect. _(ignorando el hecho de que no se puede heredar de clases `static`)_ +> +> El polimorfismo y principio de sustitución (se verá proximamente) son las verdaderas estrellas de la herencia y algunas de las bases fundamentales de la programación orientada a objetos. + +## Sintaxis + +```csharp +class A { + // ... +} + +class B : A { // B hereda las funcionalidades de A + // (y con ello sus datos). + // ... +} +``` + +## Recordatorios sobre "tipos" en programación + +Representan conceptos: agrupan los datos y funcionalidades que deben cumplir todos los objetos de ese tipo. +- Tipos de referencia: clases + - Heredan de `System.Object`. ++ Tipos por valor: structs + - Heredan de `System.ValueType` (que a su vez hereda de `System.Object`). + - No se puede heredar explicitamente de `System.ValueType`. + - Pero sí usar como tipo de parámetro, etc. + +- Campos de clase y instancia. +- Clases `static` y no `static`. + + CONSECUENCIAS???? + > `static` y la herencia + > - No se puede heredar de clases `static`. + >- Las clases `static` solo pueden heredar de `object`. \ No newline at end of file