Programació amb C# .NET Tema 4 (a): Introducción a la POO Jordi Linares i Pellicer Índice ! Antecedentes históricos ! Razones para usar OO ! Paradigmas de programación ! Noción de Objeto ! Conceptos en la OO ! Lenguajes OO Antecedentes históricos " La aparición de OO refleja y resume la historia de la computación como un todo. " La POO son un conjunto de técnicas que nos permiten mejorar enormemente el proceso de producción de software " Simula 67, conceptos de clase y herencia. " El término “Orientado a Objetos” se introdujo con Smalltalk (70, PARC) " El último gran paso lo da Bjarne Stroustrup en 1986 creando el C++, definido en su libro: The C++ Programming Language Idea básica Manejar los datos y los procedimientos en una única entidad: el objeto. Un programa es un objeto, que a su vez está formado de objetos. Razones para usar OO " Aumento de productividad: reutilización " Manejo de la complejidad " Calidad " Mantenibilidad Reutilización vs. SW tradicional: " Se construyen componentes ÚNICOS Y NO INTERCAMBIABLES. ! se ensamblan “a mano” ! dificultad para entender el código realizado por otros para extender y refinar el producto. " Raramente sobreviven y evolucionan (al menos) 10 años. ! No " son adaptables a los entornos cambiantes: incremento del potencial Hardware, SO, expectativas de usuarios, etc. Reutilización del SW en OO " La OO enfatiza la reutilización ! uso de librerías de componentes, en particular a través de conceptos como encapsulación y herencia. ! los componentes tienden a tener una alta cohesión semántica por el encapsulamiento de código y datos. ! utiliza la técnica de desarrollo incremental e iterativo. ! técnicamente la reutilización es “más fácil”, aunque no se garantice!. Paradigmas de programación " Paradigma Imperativo (1) ! Expresa algoritmos que se realizan basados en el funcionamiento de la arquitectura Von Neumann. ! Los datos se almacenan en variables (referencias abstractas de una dirección de memoria) y las operaciones se llaman instrucciones. ! Su realización es llamada ejecución. ! La ejecución de un PROGRAMA IMPERATIVO parte de un estado inicial (Ei) y termina en un estado final (Ef). ! El paso del estado inicial al estado final se realiza mediante una serie de transiciones que se producen al ejecutarse las instrucciones del programa de forma secuencial. ! El paradigma se completa con otras características que dan mayor flexibilidad de cálculo: " tipos de datos y declaraciones " instrucciones de control de flujo y condicionales, etc. " Paradigma ! Un Orientado a Objetos OBJETO es un ente autónomo que pertenece a una cierta CLASE que define su estructura y las operaciones utilizables. ! En el paradigma imperativo se crea una jerarquía de programas, módulos o subrutinas que utilizan los datos. ! En el paradigma OO la jerarquía la forman los objetos. Noción de Objeto " Un objeto integra comportamiento y estado en una sola unidad de razonamiento y de programación: comportamiento + estado = objeto Los objetos representan una “cosa” del mundo real, por ejemplo, una cuenta bancaria M3 M2 Objeto 1 M1 M4 Interactúan entre sí por el paso de mensajes... mensaje 2 M4 M3 Object 1 M1 M2 Object M3 2 M1 M4 M2 mensaje 1 mensaje 3 M3 M2 Object 3 M4 Noción de Objeto M1 Los objetos ocultan detalles de implementación... Cta_banco : extraer depositar : Array : agregar buscar : El cliente “ve” sólo la interfaz Coche : repostar alquilar : Los objetos heredan (reutilizan) propiedades de objetos más genéricos M3 M4 Persona M1 M2 Heredado Propio activo pasivo calcular%() nombre dirección obtenerEdad() M3 M4 Cliente M1 nombre dirección obtenerEdad() M2 En definitiva, los objetos: " Representan una parte del mundo real, algo tangible, visible. " Encapsulan la parte estática (datos) y la dinámica (funciones). " Se comunican a través del paso de mensajes. " Pueden heredar atributos y comportamiento de otros objetos. Estructura y comportamiento de objetos similares se define en su clase común. " Conceptos en la OO " Clases y Objetos " Abstracción " Encapsulación " Herencia " Comunicación interobjetual " Polimorfismo " Clases y Objetos ! Una clase se puede considerar como una descripción genérica (en cuanto a estructura y comportamiento) para un conjunto de objetos. ! En la clase se declaran todas las propiedades (estáticas y dinámicas) de los miembros que pertenecen a esa clase. ! Un objeto es un ejemplar de una clase determinada. ! Los objetos se caracterizan por: Identidad: Los objetos se distinguen unos de otros " Comportamiento: Los objetos pueden realizar tareas " Estado: Los objetos contienen información " ! Instanciación Es la operación que permite la creación de representantes físicos de las clases: Objetos, instancias, ejemplares, ... Ejemplo de instanciación: Persona José Perez c/ Reus 35, 27 CLASE: PERSONA ------------------------Nombre, Direccion, Edad ------------------------ObtenerEdad ObtenerEdad() ... Persona Juan Díaz c/ Colón 7, 35 ... ObtenerEdad() " Abstracción ! Visión simplificada de cierta parte de la realidad, que realza ciertos detalles o propiedades y suprime otros. ! Permite la elección de los detalles esenciales y centrarse en ellos. ! Básica para diseñar software de calidad. " Encapsulación ! Un objeto puede tener una interface pública y una representación privada claramente diferenciadas. ! Los datos privados del objeto sólo se permiten modificar a través operaciones propiamente definidas. ! La encapsulación de datos y sucesos es básica en el paradigma objetual: permite el control y el cambio. Ejemplo de encapsulación: " Herencia ! “Un conjunto de abstracciones a menudo se relacionan en sus características y comportamientos, de tal forma que pueden agruparse en niveles, simplificando grandemente el entendimiento del problema”. ! Es el principio por el cual se dice que el conocimiento de una categoría más general es aplicable también a la categoría más específica. ! Una subclase es una clase que hereda comportamiento y estructura de otra clase (superclase). ! La subclase puede añadir sus propias propiedades. ! Herencia múltiple: una subclase hereda de más de una superclase. Ejemplo 1: CLASE A CLASE B superclase subclase CLASE C CLASE D D “es un” C CLASE E E “es un” D y también un B Ejemplo 2 Escrito Libro Editorial Precio Autor Título Artículo Revista Fecha Comunicación interobjetual " " " " " Un objeto accede a otro enviándole un mensaje Cuando eso ocurre, el receptor ejecuta el método correspondiente al mensaje Un mensaje consiste en un nombre de método más cualquier argumento adicional que es enviado por un objeto (cliente) a otro (servidor) El conjunto de mensajes a los que un objeto responde caracteriza su comportamiento El método asociado a un mensaje es el algoritmo detallado que lo implementa (privado). Polimorfismo " Cualidad que poseen los objetos para responder de distinto modo ante el mismo mensaje. " Implica que el objeto que envía un mensaje no necesita conocer la instancia de la clase receptora. " Permite detectar y aprovechar similitudes entre distintas clases de objetos: objetos distintos que respondan a un mismo mensaje pueden ser tratados de la misma forma por el remitente. Ejemplo: Polígono Triángulo area() mover() area() Rectángulo area() Lenguajes OO " " " " " En 1986, E. Stroustrup extendió el lenguaje de programación C a C++, es decir C con conceptos de clases y objetos, también por esas fechas se creo desde sus bases el lenguaje EIFFEL. En 1995 apareció el más reciente lenguaje OO, Java desarrollado por SUN, que hereda conceptos de C++. El lenguaje de desarrollo más extendido para aplicaciones Web, el PHP 5, trae todas las características necesarias para desarrollar software orientado a objetos. Además de otros lenguajes que fueron evolucionando, como el Pascal a Delphi. Finalmente también otros lenguajes script como el ActionScript que si bien no es totalmente orientado a objetos pero sí posee algunas características. Programació amb C# .NET Tema 4 (b): Programación Orientada a Objetos con C# Jordi Linares i Pellicer Índice ! Introducción ! Espacios con nombre (Namespaces) ! Definición de Clases ! Miembros de una clase ! Interfaces ! Sobrecarga de operadores ! Clases Parciales ! Clases Estáticas Introducción ! Tradicionalmente el código se reutilizaba por el sistema de cortar aquí y pegar allá: " Manual " Difícil mantenimiento posterior " Nunca se acaba de cerrar nada ! Los objetos permiten encapsular datos y métodos, herencia, polimorfismo, interfaces, … ! C# es un lenguaje orientado a objetos. ! Se estudiará cómo crear clases propias para utilizarlas creando objetos, así como otros conceptos relacionados con la programación orientada a objetos (POO). Espacios con nombre (Namespaces) ! En la plataforma .NET todos los objetos se organizan en espacios con nombre. ! Un espacio con nombre define un grupo de miembros distintos, o ámbito, que comparten un nombre y un propósito común. ! Un espacio con nombre puede contener a otros espacios con nombre dando lugar a una jerarquía: System Windows Forms Web Services UI ! Definición: ! Namespaces anidados: ! Acceso cualificado a las definiciones de los namespaces: ! ! namespace Espai1 { class Classe1 { ... } } namespace Espai1 { namespace SubEspai1 { class Classe2{…} } } ! Espai1.Classe1… ! System.Console.ReadLine(); Using permite hacer referencia a namespaces: ! Using System ! Using System.Windows.Forms ! Using System.Console # ERROR, porque Console es una clase Dos clases pueden tener el mismo nombre pero en espacios de nombre diferentes, en ese caso, se han de usar referencias completas o usar un alias. Ejemplo: namespace MaClasses { namespace Espai1 { public class Mostra { public void MostraMissatge() { } Console.WriteLine(“Hola des de Espai1.Mostra"); } } namespace Espai2 { public class Mostra { public void MostraMissatge() { } } } } Console.WriteLine(“Hola des de Espai2.Mostra "); using System; using MaClasses.Espai1; // con alias: using Esp1 = MaClasses.Espai1 using MaClasses.Espai2; // con alias: using Esp2 = MaClasses.Espai2 namespace App1 { class ClasseExemple { [STAThread] static void Main(string[] args) { // Mostra m = new Mostra(); # Error por referencia ambigua // Tenemos que usar una referencia completa la clase: MaClasses.Espai1.Mostra m = new MaClasses.Espai1.Mostra(); m.MostraMissatge(); // … o podemos usar tambien un alias si lo hemos definido Esp2.Mostra k = new Esp2.Mostra(); k.MostraMissatge(); } } } Definición de Clases ! Las clases permiten crear nuevos tipos de datos. ! Las clases se definen dentro de un namespace mediante la palabra clave class seguida del identificador de la clase. ! A diferencia de los demás tipos de datos las clases pueden derivarse unas de otras. ! Contienen datos, métodos y propiedades ! Una clase puede incluir otras clases. ! Las clases pueden implementar interfaces. ! También pueden incluir delegados y eventos. ! Modificadores de acceso: public La clase o miembro es accesible en cualquier ámbito. protected Se aplica sólo a miembros de la clase. Indica que sólo es accesible desde la propia clase y desde las clases derivadas. private Se aplica a miembros de la clase. Un miembro privado sólo puede utilizarse en el interior de la clase donde se define, por lo que no es visible tampoco en clases derivadas. internal La clase o miembro sólo es visible en el proyecto (ensamblado) actual. internal protected Visible en el proyecto (ensamblado) actual y también visible en las clases derivadas. ! Todas las clases derivan implícitamente de la clase base System.Object y heredan todos sus métodos públic y protected: Finalize(), Equals(), GetType(), ToString(),…, etc. ! Constructores y Destructores " En C# existen unos métodos específicos para controlar la creación (constructores) y la eliminación de objetos (destructores). " En C# si no se definen se heredan por defecto de System.Object. " Los constructores tienen el mismo nombre de la clase y no devuelven ningún valor. " Pueden tomar o no argumentos (constructor por defecto). class MaClasse { public MaClasse() { // Codi del constructor per defecte } public MaClasse(int maEnt) { // Constructor con parámetro maEnt } } " Puede haber múltiples constructores en una clase (si cuenta con diferentes argumentos), pero cada clase sólo puede contar como máximo con un destructor. " El destructor no retorna ningún valor y no tiene argumentos. ~MaClasse() { // Códi del destructor. } " El constructor de la clase se ejecuta en el momento que se utiliza new para crear un nuevo objeto de esa clase. " El destructor de la clase se ejecuta para cierto objeto cuando ya no hay ninguna referencia a ese objeto. De ello se ocupa el recolector de basura (garbage collector) de la plataforma .NET. (ya no existe el delete en C#) " Para hacer referencia explícita dentro de la clase al objeto que llama al método usaremos this. " Ejemplo: namespace POO { class Persona { string Nom, Cognoms; ushort Edat; // constructor per defecte public Persona () { Console.WriteLine("Constructor per defecte de } Persona.Sense arguments "); } } // constructor amb arguments public Persona(string Nom, string Cognoms, ushort Edat) { this.Nom = Nom; this.Cognoms = Cognoms; this.Edat = Edat; Console.WriteLine("Constructor de {0} {1}", Nom, Cognoms); } //Destructor ~~Persona() { Console.WriteLine("Destruït: {0} {1} ", Nom, Cognoms); Console.ReadLine(); } public void MostraDades() { Console.WriteLine("\nNom: {0}\nCognoms: {1}\nEdat: {2}", Nom, Cognoms, Edat); } class Class1 { [STAThread] static void Main(string[] args) { Persona p, q; p = new Persona(); q = new Persona("Pepe", "Pérez", 23); p.MostraDades(); q.MostraDades(); Console.WriteLine("\n\n---Final de l'aplicació---"); Console.ReadLine(); } } ! Herencia " Es el mecanismo para definir una nueva clase (clase derivada) partiendo de una clase existente (clase base) " La herencia permite la reutilización de código. " La clase derivada hereda todos los miembros de su clase base, excepto los que son privados. " Todas las clases derivan implícitamente de Object. " C# sólo permite heredar de una sola clase. " Si una clase deriva de otra clase base se indica tras el nombre de la clase con dos puntos y el nombre de la clase de la cual deriva: <NomDer>:<NomBase> " Para llamar al constructor de la clase base: public Quadrat(string nom) : base(nom){ … } " Ejemplo de herencia (derivación) class animal { // hereda de Object protected int peso=100; protected int talla=50; } class perro : animal {// perro hereda de la clase animal public void mostrarTodosDatos() { Console.WriteLine(peso.ToString() + " " + talla.ToString()); } } desde Main(): perro p = new perro(); p.mostrarTodosDatos(); " Cuando no interesa que se derive de una clase (porque se trata de una clase final) se usa el modificador sealed (sellada) delante de class: public sealed class perro : animal{...} " Muchas clases de .NET Framework son selladas: String, StringBuilder, etc. " En cambio, si la clase sólo debe actuar como clase base de otras clases se denomina clase abstracta y se usa el modificador abstract en la declaración: public abstract class animal {...} # No es posible instanciar objetos directamente de una clase abstracta, es necesario derivar. Miembros de una clase ! En una clase se definen campos, propiedades y métodos. ! Cada miembro tiene su propio nivel de accesibilidad: private, public, protected, internal, protected internal. ! Además, los miembros definidos estáticos (static) son compartidos por todos los objetos de la clase y se acceden directamente: <nombreClase>.<nombreMiembroEstatico> ! Campos Se definen como las variables añadiendo su nivel de accesibilidad, además de static y const opcionalmente. " Las variables estáticas se acceden por la clase y nunca por instancias de la clase. " class MaClasse { public int MaEnt; //primera lletra en majúscula public static int MaEntEstat; // public const int MaConst=120; // constant pública } ! Métodos " Se definen como las funciones indicando su nivel de accesibilidad y static de forma opcional. Métodos sobrecargados: permiten tener en una misma clase varios métodos con el mismo nombre pero con diferentes argumentos. Se aplica también a los contructores. " A la definición del método pueden añadirse las palabras reservadas: virtual, abstract, override o extern. " " Ejemplo de sobrecarga: class ObjGeometrico { public static void Dibuixa(int x, int y) { // dibuixa en un punt } public static void Dibuixa(int color){ // pinta la pantalla de color } public static void Dibuixa(int x, int y, int color) { // dibuixa en un punt i ompli de color } } class Quadrat : ObjGeometrico { public static void Dibuixa(int x1, int y1, int x2, int y2) { // dibuixa un quadrat } public static void Dibuixa(int x1, int y1, int x2, int y2, int color) { // dibuixa un quadrat i l'ompli de color } } " Métodos virtuales. ! Permiten que las clases sean polimórficas. ! Se usa la palabra clave virtual. ! Un método virtual especifica una implementación de un método que puede ser sustituida por polimorfismo en una clase derivada. Un método no virtual especifica la única implementación de un método. No es posible sustituir por polimorfismo un método no virtual en una clase derivada. Los métodos virtuales no son ni estáticos ni privados. ! ! class ObjGeometrico { protected string nom; ... public virtual void Dibuixa(int x, int y) { // dibuixa l’objecte en la pos x,y } public string MostraNom() { return nom; } } " Sustitución de métodos (override): ! Un método override especifica otra implementación de un método virtual definido en una clase base. ! El método override debe coincidir exactamente con su método virtual heredado asociado. ! Un método override se puede sustituir también en las clases derivadas. class Quadrat : ObjGeometrico { public override void Dibuixa(int x, int y) { // nova implementació del mètode // per a dibuixar el quadrat } public override string MostraNom() { return “Quadrat” + nom; } $ERROR MostraNom no es virtual!! } " Ocultación de métodos ! ! ! En ocasiones, un método heredado no implementa en la clase derivada exactamente lo que se desea. Al redefinirlo, el método de la clase base queda oculto. Se utiliza el modificador new en el método de la clase derivada para indicar que se redefine el método. class ObjGeometricoImp: ObjGeometrico { new public static void Dibuixa(int x, int y) { // nova implementació del mètode // oculta el mètode de la classe base Console.WriteLine(“Punt a impressora”); } } ! Propiedades " " " " " Aparecen en la clase como campos de datos. Las propiedades tienen un tipo, pero la asignación y lectura de las mismas se realiza a través de métodos de lectura y escritura. Con las propiedades se puede limitar el acceso a un campo permitiendo sólo la lectura y también se puede realizar cualquier comprobación cuando se asignan valores a la propiedad. Con Intellisense de Visual Studio 2005 se inserta directamente una nueva propiedad: Insertar fragmento de código#prop Ejemplo: private string nombre; public string Nombre { get { return } set { nombre } } // camp privat // propietat pública nombre; = value; Propiedad de lectura / escritura " " Para indicar que una propiedad es de sólo lectura o sólo escritura hay que omitir el apartado set o get repectivamente. Ejemplo: class Ficha { private string nombre; private int anyo; public string Nombre //propiedad de sólo lectura { get { return “El teu nom és: “ + nombre; } } public int Anyo //propiedad de lectura/escritura { get { return anyo; } set { if (value>1900) // comprovem si és correcte anyo = value; else Console.WriteLine(“Només anys >1900”); } } Interfaces ! Muchas veces al heredar de un objeto lo único que queremos es que herede un comportamiento. Es decir, asegurarnos que implemente unos métodos concretos para aplicar el polimorfismo. También hay situaciones en las que nos gustaría heredar de varias clases: pero C# no permite herencia múltiple. Una interfaz es la definición de un conjunto de métodos, propiedades, etc. para los que no se da implementación pero que las clases hijas sí que deben implementar. Una interfaz no contiene tipos, ni campos, ni modificadores de acceso (sólo public) Al no tener implementación los interfaces no se pueden instanciar. Una clase puede implementar varias interfaces separándolos por comas. Una clase ha de implementar todos los métodos de interfaz heredados ! Declaración: ! ! ! ! ! ! ! Los nombres de interfaces empiezan con “I”mayúscula interface IPalClave { int NumLinea( ); string Palabra( ); } Métodos sin cuerpo Sin especificación de acceso IPalClave « interface » NumLinea( ) Palabra( ) Ejemplo: Editor de formas geométricas Interfaces ! " Definición: Interfaces public interface IFigura { void Dibujar(); float Area(); float Perimetro(); } public class Cuadrado : IFigura { protected float lado; public Cuadrado(float l) { this.lado=l; } public float Area() { return lado*lado; } public float Perimetro() { return 4*lado; } public void Dibujar() { System.Console.WriteLine("[]"); } } Interfaces public class Circulo : IFigura { protected float radio; protected const float PI=3.14159F; public Circulo(float radio) { this.radio=radio; } public float Area() { return PI*(float)Math.Pow(radio,2); } public float Perimetro() { return 2*PI*radio; } public void Dibujar() { Console.WriteLine("O"); Interfaces " public interface IFigura { void Dibujar(); float Area(); float Perimetro(); } Obligación de implementar todos los métodos de la interfaz Uso de las interfaces. Una interfaz puede hacer referencia a cualquier clase que la implemente: Circulo fig1=new Circulo(1); Cuadrado fig2=new Cuadrado(2); IFigura[] Figuras = new IFigura[2]; //array de interfaces IFigura f; //referencia a la interfaz f=fig1; f.Dibujar(); Console.WriteLine("PERIMETRO=“ + f.Perimetro() ); Console.WriteLine(“AREA="+ f.Area() ); f=fig2; f.Dibujar(); Console.WriteLine("PERIMETRO=“ + f.Perimetro() ); Console.WriteLine(“AREA=“ + f.Area() ); Figuras[0] = new Circulo(4); Figuras[1] = new Cuadrado(2); Sobrecarga de Operadores ! C# permite la sobrecarga de operadores para hacer algunas operaciones más intuitivas: +, -, * , /, <,>… etc. ! Hay que usarlo sólo cuando su aplicación resulta más clara que con la llamada a un método. ! Ejemplos: " Sumar, restar, etc. dos arrays. " Operaciones con números complejos. " Comparar cadenas usando >,<, etc. Todos los operadores sobrecargados se definen public y static seguido del tipo devuelto, la palabra clave operator i el operador que se quiere sobrecargar. ! ! Ejemplo: sumar y restar dos vectores de enteros class Vector { int[] v; public Vector(params int[] v) { this.v = new int[v.Length]; for (int i = 0; i < v.Length; i++) this.v[i] = v[i]; } public static Vector operator +(Vector v1, Vector v2) { int[] minV, maxV; if (v1.v.Length > v2.v.Length) { minV = v2.v; maxV = v1.v; } else{ minV = v1.v; maxV = v2.v; } static void Main(string[] args) { Vector v1 = new Vector(1,2,3,4); Vector v2 = new Vector(1,2,3,4,5,6); int[] suma = new int[maxV.Length]; int i,j; Vector v3 = v1 + v2; for (i = 0; i < minV.Length; i++) suma[i] = minV[i] + maxV[i]; for (j=i; j<maxV.Length;j++) suma[j] = maxV[j]; return new Vector(suma); } public override string ToString() { string s=""; foreach (int i in this.v) s += i + " "; return s; } } Console.WriteLine(v3.ToString()); Console.ReadLine(); } Clases Parciales ! Permiten dividir la definición de una clase, estructura o interfaz en ficheros separados. ! Esto es lo que ocurre con el código generado por Visual Studio. ! Es útil cuando: ! " Varios programadores quieren trabajar a la vez con la misma clase, " El fichero se hace muy grande, " Los métodos se quieren tener por separado. Definición: //fichero ClasePart1.cs partial class ClaseParcial { public void Metode1() { } } //fichero ClassPart2.cs partial class ClaseParcial { public void Metode2() { } } #Al compilar habrá una clase ClaseParcial con dos métodos. ! Las Interfaces aplicadas a una clase parcial se aplica a todas las partes de la clase: public partial class MaClasse : IMaInterface1 { .... } public partial class MaClasse : IMaInterface2 { .... } equivale a: public class MaClasse : IMaInterface1, IMaInterface2 { ... } Clases Estáticas ! Una clase estática sólo contiene miembros estáticos. ! Una clase estática nunca se instancia. ! Definición: static class ClasseEstatica { public static void MetodeEstatic(){..} } ! Uso directo del método: ClasseEstatica.MetodeEstatic();