Otro ejemplo polimorfismo

 class Persona
    {
        private string _nombre;

        public Persona(string nombre)
        {
            Console.WriteLine("Constructor persona " + nombre);
            this.Nombre = nombre;
        }
        public string Nombre
        {
            set { this._nombre = value; }
            get { return this._nombre; }
        }
        public virtual string saludo()
        {
            return "Hola "+Nombre+" que tal";
        }
      
    }

    class Empleado :Persona
    {
        public Empleado(string nombre, int sueldo=0) : base(nombre)
        {
            Console.WriteLine("Constructor empleado " + nombre);

            this.Cargo = "Empleado";
        }
        public int Sueldo { get; set; }
        private string _cargo;
        public string Cargo {
            set { this._cargo = value; }
            get { return this._cargo; } }
        public override string saludo()
        {
            return "Hola empleado " + Nombre + " ¿Todo bien?";
        }
        public virtual double sueldoNeto()
        {
            return Sueldo * .85;
        }
       
    }
    class Gerente : Empleado
    {
        public int Bono { get; set; }
        public int Dietas { get; set; }
        public Gerente(string nombre) : base(nombre)
        {
            Console.WriteLine("Constructor gerente " + nombre);

            this.Cargo = "Gerente";

        }

        public Gerente(string nombre, int sueldo) : base(nombre, sueldo) { }
        public Gerente(string nombre, int sueldo, int dietas) : this(nombre, sueldo)
        {
            Dietas = dietas;
        }
        public override string saludo()
        {
            return "Hola Sr. " + Nombre + " ¿Desea alguna cosa?";
        }
        public override double sueldoNeto()
        {
            return base.sueldoNeto()+Dietas;
        }
    }
    sealed class Direccion : Gerente
    {
        public int StockOptions { get; set; }
        public Direccion(string nombre) : base(nombre, 100) {
            Console.WriteLine("Constructor direccion " + nombre);
        }
        public Direccion(string nombre, int sueldo) : base(nombre, sueldo) { }
        public Direccion(string nombre, int sueldo, int dietas):base(nombre, sueldo, dietas) { }
        public Direccion(string nombre, int sueldo, int dietas, int stockoptions) : this(nombre, sueldo, dietas)
        {
            this.StockOptions = stockoptions;
        }
        public override string saludo()
        {

            return "Buenos días Sr. " + Nombre + " Estamos a sus órdenes";
        }
        public override double sueldoNeto()
        {
            return base.sueldoNeto()+StockOptions*.5;
        }
    }
    class Cliente : Persona
    {
        public Cliente(string nombre) : base(nombre)
        {
        }
    }

Uso:

  Empleado eva = new Empleado("Eva",1200);
         
           
            Gerente ana = new Gerente("Ana");
            ana.Sueldo = 1700;
            ana.Dietas = 200;
            Direccion rosa = new Direccion("Rosa");
            rosa.Sueldo = 2500;
            rosa.Dietas = 300;
            rosa.StockOptions = 100;
            Console.WriteLine(rosa.sueldoNeto());
            Empleado[] plantilla = { eva, ana, rosa };
            double total = 0;
            foreach(Empleado item in plantilla)
            {
                total += item.sueldoNeto();
            }
            Console.WriteLine(total);

Herencia en c# y polimorfismo

 class Persona
    {
        private string _nombre;

        public Persona(string nombre)
        {
            Console.WriteLine("Constructor persona " + nombre);
            this.Nombre = nombre;
        }
        public string Nombre
        {
            set { this._nombre = value; }
            get { return this._nombre; }
        }
        public virtual string saludo()
        {
            return "Hola "+Nombre+" que tal";
        }

    }

    class Empleado :Persona
    {
        public Empleado(string nombre) : base(nombre)
        {
            Console.WriteLine("Constructor empleado " + nombre);

            this.Cargo = "Empleado";
        }
        private string _cargo;
        public string Cargo {
            set { this._cargo = value; }
            get { return this._cargo; } }
        public override string saludo()
        {
            return "Hola empleado " + Nombre + " ¿Todo bien?";
        }

    }
    class Gerente : Empleado
    {
        public int Bono { get; set; }
        public Gerente(string nombre) : base(nombre)
        {
            Console.WriteLine("Constructor gerente " + nombre);

            this.Cargo = "Gerente";

        }
        public Gerente(string nombre, int bono) : this(nombre)
        {
            this.Bono = bono;

        }
        public override string saludo()
        {
            return "Hola Sr. " + Nombre + " ¿Desea alguna cosa?";
        }
    }
    sealed class Direccion : Gerente
    {
        public Direccion(string nombre) : base(nombre, 100) {
            Console.WriteLine("Constructor direccion " + nombre);
        }
        public override string saludo()
        {
            return "Buenos días Sr. " + Nombre + " Estamos a sus órdenes";
        }
    }

Ejemplo de uso:

  Persona[] plantilla = { new Persona("Eva"), new Empleado("Juan"),new Empleado("Ana"),
            new Gerente("Rosa"), new Gerente("Luis"), new Direccion("Laura")};
            foreach(Persona empleado in plantilla)
            {
                Console.WriteLine(empleado.saludo());
            }

Ejercicio Producto

Vamos a definir una clase ‘Producto’ con las propiedades nombre y precio, ambas obligatorias en el constructor.

Vamos a crear una función PVP que nos devuelve el precio mas el 21% de iva.

De ahí derivamos la clase Oferta que la función PVP es la misma que en el anterior pero aplicando un 10% de descuento.

Ejercicio clases y herencia

Vamos a crear la clase Persona con las propiedades nombre (obligatoria) y DNI. Crearemos un método ‘saludo’ que nos devuelva un string con ‘Hola’+nombre

De ahí vamos a derivar la clase ‘caballero’ que tendrá la propiedad ‘tratamiento’ (obligatoria) . Sobre escribiremos el método ‘saludo’ para que devuelva ‘Hola’+tratamiento+nombre.
Añadiremos la propiedad renta de tipo int.

Vamos a derivar la clase ‘plebeyo’. Sobre escribiremos el método saludo para que devuelva ‘Hola’+nombre+’¿Qué pasa?’

Poned los getters y setters que hagan falta, pero que sea obligatorio poner un valor.

class Persona {
    private $nombre;
    private $dni;
    function __construct($nombre) {
        $this->nombre = $nombre;
    }
    function saludo() {
        return "Hola " . $this->nombre;
    }
    function __get($name) {
        return $this->$name;
    }
    function __set($name, $value) {
        if (empty($value)) {
            throw new Exception("La propiedad $name no puede estar vacía");
        }
        $this->$name = $value;
    }
}

class Caballero extends Persona{
    protected $tratamiento;
    protected $renta;
    function __construct($nombre,$tratamiento) {
        parent::__construct($nombre);
        $this->__set("tratamiento",$tratamiento);
    }
    function saludo(){
        return "Hola ".$this->tratamiento." ".$this->nombre;
    }
}

class Plebeyo extends Persona{
    function saludo(){
        return parent::saludo()." ¿Qué pasa?";
    }
}

Ejemplo herencia

<?php

/**
 * Description of Herencia
 *
 * @author incid
 */
class Empleado {

    private $nombre;

    function __construct($nombre) {
        $this->nombre = $nombre;
    }

    function __get($name) {
        return $this->$name;
    }

    function __set($name, $value) {

        if (empty($value)) {
            throw new Exception("No se puede poner valores vacíos");
        }
        $this->$name = $value;
    }

    function saludo() {
        echo "Hola";
    }

}

class Gerente extends Empleado {

    private $bonus;

    function __construct($nombre, $bonus) {
        parent::__construct($nombre);
        $this->__set("bonus", $bonus);
    }

    function saludo() {
        parent::saludo();
        echo "Los gerentes saludan así: Holi";
    }

    function despedida() {
        echo "Adios muy buenas";
    }

}

class Gerente2 extends Empleado {

    private $bonus;

    function __construct($nombre, $bonus) {
        parent::__construct($nombre);
        $this->setBonus($bonus);
    }

    function getBonus() {
        return $this->bonus;
    }

    function setBonus($bonus) {
        $this->bonus = $bonus;
    }

}

$juan = new Empleado("Juan Pérez");
$juan->nombre = "Pepito";
$juan->saludo();
//$juan->despedida(); //ERROR
var_dump($juan);
$eva = new Gerente("Eva Pi", 400);
$eva->saludo();
$eva->despedida();
//$eva->bonus=0;
var_dump($eva);

Ejercicio clases constructor y getters mágicos

Vamos a crear la clase ‘Cliente’ con las siguientes propiedades privadas:

Nombre
NIF
Pais
Importe

Vamos a crear un constructor que pida obligatoriamente el Nombre y el NIF y vamos a crear getters y setters mágicos.

Los valores no pueden estar vacíos, el NIF tiene que empezar por una letra y tener una longitud de 9 caracteres y el importe no puede ser negativo.

Probad todas las características.

class Cliente {

    private $nombre;
    private $nif;
    private $pais;
    private $importe;

    function __construct($nombre, $nif) {
        $this->nombre = $nombre;
        $this->nif = $nif;
    }

    function __get($name) {
        if (!property_exists($this, $name)) {
            throw new Exception("La propiedad $name no existe");
        }
        return $this->$name;
    }

    function __set($name, $value) {
        if (!property_exists($this, $name)) {
            throw new Exception("La propiedad $name no existe");
        }
        if (empty($value)) {
            throw new Exception("La propiedad $name no puede estar vacía");
        }
        if($name=="importe" && $value<0){
             throw new Exception("El importe no puede ser negativo");
        }
        if($name=="nif" && $this->checkNif($value)) {
            throw new Exception("NIF incorrecto");
        }
        $this->$name = $value;
    }
    private function checkNif($nif){
        return (strlen($nif)!=9 || strtoupper(substr($nif, 0,1))<"A"
                || strtoupper(substr($nif, 0,1))>"Z");
    }

}

$pepe=new Cliente("Pepe", "B61235712");

$pepe->nif="B12345678";
$pepe->importe=500;

echo $pepe->nombre;

var_dump($pepe);

Combinación setters/getters mágicos y estilo Java

class Libro {

    private $titulo;
    private $autor;
    private $paginas;
    function getTitulo() {
        return $this->titulo;
    }

    function getAutor() {
        return $this->autor;
    }

    function getPaginas() {
        return $this->paginas;
    }

    function setTitulo($titulo) {
        $this->titulo = $titulo;
    }

    function setAutor($autor) {
        $this->autor = $autor;
    }

    function setPaginas($paginas) {
        $this->paginas = $paginas;
    }

        function __construct($titulo) {
        $this->__set("titulo",$titulo);
    }

    function __get($name) {
         $metodo="get$name";
        if (!method_exists($this, $metodo)) {
            throw new Exception("La propiedad $name no existe");
        }
        return $this->$metodo();
    }

    function __set($name, $value) {
        $metodo="set$name";
        if (!method_exists($this, $metodo)) {
            throw new Exception("La propiedad $name no existe");
        }
        if (empty($value)) {
            throw new Exception("El valor $name no puede estar vacío");
        }
        if ($name == "paginas" && ($value < 10 || $value > 1000)) {
            throw new Exception("Páginas entre 10 y 1000");
        }
        $this->$metodo($value);
    }

}

Getters/Setters mágicos

class Libro {

    private $titulo;
    private $autor;
    private $paginas;

    function __construct($titulo) {
        $this->titulo = $titulo;
    }

    function __get($name) {
        if (!property_exists($this, $name)) {
            throw new Exception("La propiedad $name no existe");
        }
        return $this->$name;
    }

    function __set($name, $value) {
        if (!property_exists($this, $name)) {
            throw new Exception("La propiedad $name no existe");
        }
        if (empty($value)) {
            throw new Exception("El valor $name no puede estar vacío");
        }
        if ($name == "paginas" && ($value < 10 || $value > 1000)) {
            throw new Exception("Páginas entre 10 y 1000");
        }
        $this->$name = $value;
    }

}

Clase Empleado

 class Empleado
    {
        private string pNombre;
        private string pDni;
        private decimal pSueldo;

        public string Nombre
        {
            get
            {
                return pNombre;
            }
            set
            {
                    Console.WriteLine("Set de nombre");
                if (value.Length < 3)
                {
                    throw new Exception("El nombre debe tener una longitud mayor de 3");
                }
                else
                {
                    this.pNombre = value;
                }
            }
        }
        public string Dni
        {
            get { return this.pDni; }
            set { this.pDni = value; }
        }
        public decimal Sueldo
        {
            get { return this.pSueldo; }
            set { this.pSueldo = value; }
        }
        public Empleado(string nombre)
        {
            Console.WriteLine("Constructor 1");
            this.Nombre = nombre;
        }
        public Empleado(string nombre, string dni) : this(nombre)
        {
            Console.WriteLine("Constructor 2");
            this.Dni = dni;
        }
        public Empleado(string nombre, string dni, decimal sueldo) : this(nombre, dni)
        {
            Console.WriteLine("Constructor 3");
            this.Sueldo = sueldo;
        }
    }

Ejercicio varias clases

Vamos a crear una clase Coche con las siguientes propiedades (todas privadas):

Marca
Modelo
Color
Velocidad

Las tres primeras las pasamos en el constructor, la velocidad la ponemos a 0.

Creamos setters y getters para todas las propiedades menos para la velocidad, para esta última sólo ponemos un getter. Comprobamos en todos los setters que el valor no esté vacío, en caso contrario lanzamos una excepción.

Vamos a crear un método acelerar y otro frenar. El primero aumenta la velocidad en 10 y el segundo la disminuye. El coche no puede tener velocidad negativa ni mayor de 140.

Crearemos el método toString que nos muestra la marca, el modelo y el color separados por espacio.

Vamos a crear la clase Carrera que tendrá las siguientes propiedades:

Nombre
Circuito
Coches

En el constructor pedimos las dos primeras, la tercera es un array vacío. Ponemos setters y getters en las dos primeras.

Crearemos un método addCoche al que le pasamos un objeto coche y se añade al array. Crearemos un método quitarCoche al que le pasamos un objeto coche y si hay un objeto de esa marca, modelo y color lo quitamos.

Primera versión:

class Coche {

    private $marca;
    private $modelo;
    private $color;
    private $velocidad=0;

    function __construct($marca, $modelo, $color) {
        $this->setColor($color);
        $this->setMarca($marca);
        $this->setModelo($modelo);
    }

    function acelerar() {
        $this->velocidad += 10;
        if ($this->velocidad > 140) {
            $this->velocidad = 140;
        }
    }

    function frenar() {
        $this->velocidad -= 10;
        if ($this->velocidad < 0) {
            $this->velocidad = 0;
        }
    }

    function __toString() {
        return $this->getMarca() . " " . $this->getModelo() . " " . $this->getColor();
    }

    function getMarca() {
        return $this->marca;
    }

    function getModelo() {
        return $this->modelo;
    }

    function getColor() {
        return $this->color;
    }

    function getVelocidad() {
        return $this->velocidad;
    }

    function setMarca($marca) {
        if (empty($marca)) {
            throw new Exception("La marca no puede estar vacía");
        }
        $this->marca = $marca;
    }

    function setModelo($modelo) {
        if (empty($modelo)) {
            throw new Exception("El modelo no puede estar vacía");
        }
        $this->modelo = $modelo;
    }

    function setColor($color) {
        if (empty($modelo)) {
            throw new Exception("El color no puede estar vacía");
        }
        $this->color = $color;
    }


}

Otra versión:

class Coche {

    private $marca;
    private $modelo;
    private $color;
    private $velocidad;

    function __construct($marca, $modelo, $color) {
        $this->setColor($color);
        $this->setMarca($marca);
        $this->setModelo($modelo);
        $this->setVelocidad(0);
    }

    function acelerar() {
        $this->setVelocidad($this->getVelocidad() + 10);
    }

    function frenar() {
        $this->setVelocidad($this->getVelocidad() - 10);
    }

    function __toString() {
        return $this->getMarca() . " " . $this->getModelo() . " " . $this->getColor();
    }

    function getMarca() {
        return $this->marca;
    }

    function getModelo() {
        return $this->modelo;
    }

    function getColor() {
        return $this->color;
    }

    function getVelocidad() {
        return $this->velocidad;
    }

    function setMarca($marca) {
        $this->checkParam($marca, "La marca no puede estar vacío");
        $this->marca = $marca;
    }

    function setModelo($modelo) {
        $this->checkParam($modelo, "El modelo no puede estar vacío");
        $this->modelo = $modelo;
    }

    function setColor($color) {
        $this->checkParam($color, "El color no puede estar vacío");
        $this->color = $color;
    }

    private function checkParam($param, $message) {
        if (empty($param)) {
            throw new Exception($message);
        }
    }

    private function setVelocidad($velocidad) {
        $this->velocidad = $velocidad;
        if ($this->velocidad > 140) {
            $this->velocidad = 140;
        }
        if ($this->velocidad < 0) {
            $this->velocidad = 0;
        }
    }

}

Carrera:

class Carrera {

    private $nombre;
    private $circuito;
    private $coches = [];

    function __construct($nombre, $circuito) {
        $this->setCircuito($circuito);
        $this->setNombre($nombre);
    }

    function addCoche(Coche $coche) {
        $this->coches[] = $coche;
    }

    function quitarCoche(Coche $coche) {
        for ($i = 0; $i < count($this->coches); $i++) {
            $c = $this->coches[$i];
            if ($c->getModelo() == $coche->getModelo() &&
                    $c->getMarca() == $coche->getMarca() &&
                    $c->getColor() == $coche->getColor()) {
                array_slice($this->coches, $i, 1);
            }
        }
    }

    function getNombre() {
        return $this->nombre;
    }

    function getCircuito() {
        return $this->circuito;
    }

    function setNombre($nombre) {
        $this->nombre = $nombre;
    }

    function setCircuito($circuito) {
        $this->circuito = $circuito;
    }

}