No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

No se trata de lo que quieres comprar, sino de quién quieres ser. Invierte en tu educación con el precio especial

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

11 Días
19 Hrs
2 Min
44 Seg

Dependency Inversion Principle

15/26
Recursos

Dependency Inversion Principle detalla que los módulos de alto nivel no deben depender de los de bajo nivel, ambos deben depender de abstracciones.

Las abstracciones no deben depender de los detalles, los detalles deben depender de las abstracciones.

Aportes 104

Preguntas 11

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Una abstracción se enfoca en la visión externa de un objeto, separa el comportamiento específico de un objeto, a esta división que realiza se le conoce como la barrera de abstracción, la cuál se consigue aplicando el principio de mínimo compromiso.
.
Pero… ¿Qué es el principio de mínimo compromiso? Se refiere al proceso por el cuál la interfaz de un objeto muestra su comportamiento específico y nada más, absolutamente nada más.
(Fuente)
.
En otras palabras la abstracción se enfoca en “que hace” sin importar en “cómo lo hace”.
.
Es como solo fijarse en el nombre de una función calcularHorasDelAño(), sin importar el código que hay dentro, solo nos quedamos con el nombre, que ya nos dice “que hace”, y no "como lo hace".

Dependency Inversion Principle


Este principio nos ayuda a definir cómo se vinculan las diferentes clases que tienen que darle servicios a otras. Un concepto que se maneja con este principio es que existen clases con alto nivel, otras con bajo nivel.

  • Alto nivel → Son aquellas que tienen que ver con la lógica del negocio.
  • Bajo nivel → Son aquellas que ayudan a que las clases de alto nivel cumplan su objetivo.

Y de lo que se encarga este principio es de que las dependencia entre estas no sea muy fuerte.

Según C. Martin:

Los módulos de alto nivel no deben depender de los de bajo nivel, ambos deben depender de abstracción.

Las abstracciones no deben depender de los detalles, los detalles deben depender de las abstracciones.


Resumen:

Este principio nos indica que debemos reducir las dependencias de los módulos que existen en nuestra aplicación.

Otra forma de decirlo es que los módulos NO DEBEN ser los encargados de crear los objetos con los que trabajan, sino que alguien más debe de crearlos y dárselos cuando lo necesiten.

Se le hizo un poco complicado entender cada uno de los principios de SOLID pero profundizare mas y trabaje en ellos, ya que son muchos los beneficios que me pueden aportar

RetoA
Problema: No respeta el principio de responsabilidad única al tener muchos métodos que no tienen que ver con ordenar.
Solución: Dividir en 3 clases distintas.
RetoB
Problema: No cumple con el principio abierto-cerrado ya que para agregar una nueva clase además de generarla se debe módificar la clase ProjectManagment.
Solución: Implementar que la función proccess de Project Managment requiera cumplir con una interfaz.
RetoC
Problema: No cumple con el principio de susbtitución de Liskov al no realizar Dog lo mismo que su clase padre.
Solución: Quitarle a Animal el método fly, agregar una interfaz FlyerAnimal y en otra clase que asi lo requiera implementarla.
RetoD
Problema: Error al no alicar segregación de interfaz, ya que el consultor no puede realizar un método en específico.
Solución Separar en 3 Interfaces la interfaz Underling Interface para evitar posibles errores y al momento de construir ver si es del tipo de interfaz compuesto.
RetoE
Problema: No respeta el principio de Inversión de dependencias al no recibir un Interfaz sino un tipo de clase en concreto en el constructor.
Solución: Cambiar el constructor para que reciba una interfaz de IManzano y que la clase Manzano la implemente.

Para el primer reto utilicé el principio Open/Close. De este modo podrémos agregar nuevos tipos de “objetos” de nuevas clases que vayamos implementando en el futuro.

<?php

    class Programmer {
        public function code() {
            return 'coding';
        }
        
        public function process() {
            code();
        }
    }
    
    class Tester {
        public function test() {
            return 'testing';
        }
        
        public function process() {
            test();
        }
    }
    
    class ProjectManagement {
        public function process(array $members) {
            foreach( $members as $member ) {
                $member->process();
            }
        }
    }
    
?>```

Comparto 4/5 retos que pude identificar y brindar una solución. (Se vale retroalimentación de ustedes).

Reto4

<?php
//Single responsibility

    class OrderTotal{
        public function calculateTotalSum(){/*...*/}
    }

    class OrderItemsGet{
        public function getItems(){/*...*/}
        public function getItemCount(){/*...*/}
    }

    class OrderItemsAction{
        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}
    }

    class Orderprint{
        public function printOrder(){/*...*/}
    }

    class OrderShow{
        public function showOrder(){/*...*/}
    }

    class OrderAction{
        public function load(){/*...*/}
        public function save(){/*...*/}
        public function update(){/*...*/}
        public function delete(){/*...*/}
    }

Reto4b

<?php
//Open & Close
    interface profile{
        public function process();
    }
    
    class Programmer implements profile
    {

        public function process(profiles $member)
        {
            return 'coding';
        }
    }
    class Tester implements profile
    {
        public function process(profile $member)
        {
            return 'testing';
        }
    }
    

Reto4c

<?php
//Liskov substitution
    interface fly{
        public function fly();
    }

    class Animal{
        
    }
    class AnimalhasWings extends Animal implements fly{
        public function fly()
        {
        }
    }
    class Dog extends Animal{
       
    }```

**Reto4d**



<?php
//Segregacion del interface
interface UnderlingInterface
{
public function collate();
}

   interface consultantgInterface
{
    public function program();

    public function filetps();
}


class Underling implements UnderlingInterface, consultantgInterface
{
    public function program()
    {
        return 'Program initech systems to deposit fractions of pennies to private account';
    }

    public function filetps()
    {
        return 'Place cover sheet on TPS report before going out';
    }

    public function collate()
    {
        return 'Collect and combine texts, information, and figures in proper order.';
    }
}

class Consultant implements consultantgInterface
{
    public function program()
    {
        return 'Outsource task to India';
    }

    public function filetps()
    {
        return 'Place cover sheet on TPS report before going out';
    }

}

class Lumbergh
{
    protected $underling;

    public function __construct(UnderlingInterface $underling)
    {
        $this->underling = $underling;
    }

    public function harass()
    {
        $this->underling->program();
        $this->underling->filetps();
        $this->underling->collate();
    }
}```

Este si la verdad no lo entendí, porque con el ejemplo que pone, si se abre una nueva forma de enviar mensajes, igual se va a tener que modificar el constructor

Segundo reto, apliqué el princpio de responsabilidad única:

class Item {

      public function calculateTotalSum(){/*...*/}
      public function getItems(){/*...*/}
      public function getItemCount(){/*...*/}
      public function addItem($item){/*...*/}
      public function deleteItem($item){/*...*/}

}

class DataBase() {

      public function load(){/*...*/}
      public function save(){/*...*/}
      public function update(){/*...*/}
      public function delete(){/*...*/}

}

class Order {
        
      public function printOrder(){/*...*/}
      public function showOrder(){/*...*/}

}
De nuevo el instructor no termina de aplicar la solución al problema.

El principio de inversión de dependencia nos ayuda a definir como se vinculan las diferentes clases que tienen que darle servicio a otras.
.
Un concepto importante que se deduce de este principio es que existen clases de alto nivel y clases de bajo nivel.

Reto4d
No lo tengo claro, pero era para hacerlo diferente a otro compañero

<?php
    interface CollateInterface
    {
      public function collate();
    }

    interface UnderlingInterface
    {
        public function program();

        public function filetps();

    }

    class Underling implements UnderlingInterface, CollateInterface
    {
        public function program()
        {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function collate()
        {
            return 'Collect and combine texts, information, and figures in proper order.';
        }

        public function process()
        {
          $this->program();
          $this->filetps();
          $this->collate();
        }
    }

    class Consultant implements UnderlingInterface
    {
        public function program()
        {
            return 'Outsource task to India';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function process()
        {
          $this->program();
          $this->filetps();
        }
    }

    class Lumbergh
    {
        protected $underling;

        public function __construct(UnderlingInterface $underling)
        {
            $this->underling = $underling;
        }

        public function harass()
        {
            $this->underling->process();
        }
    }

    interface Workable{
        public function process();
    }

    class Programmer implements Workable
    {
        public function process()
        {
            return 'coding';
        }
    }
    class Tester implements Workable
    {
        public function process()
        {
            return 'testing';
        }

    }
    class ProjectManagement
    {
        public function process(Workable $member)
        {
            $member->process(); 
        }
    }

RETOS
Reto A:
Problema:
Rompe el principio S.
Solución:
Divido la clase Order obteniendo lo siguiente:

    class Order {
        public function calculateTotalSum(){/*...*/}
        public function getItems(){/*...*/}
        public function getItemCount(){/*...*/}
        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}
    }

    class ViewOrder {
        public function printOrder(){/*...*/}
        public function showOrder(){/*...*/}
    }

    class OrderService {
        public function load(){/*...*/}
        public function save(){/*...*/}
        public function update(){/*...*/}
        public function delete(){/*...*/}
    }

Reto B:
Problema:
Rompe el principio O.
Solución:
Utilizamos abstracción para hacer extensible la clase Programmer.

     class ProjectManagement {
        public function process($member) {
                $member->process();
        }
    }

Reto C:
Problema:
Rompemos el principio L.
Solución:
Dogs are Animals but dogs can’t fly. Podemos armar una jerarquía de herencia con animales que sí pueden volar y animales que no pueden volar.

   class Animal {
    }
   class AnimalFly extends Animal {
        public function fly() {}
    }
   class AnimalNotFly extends Animal {
        public function watchTV() {}
    }

    class Dog extends AnimalNotFly {
        public function watchTV() {}
    }
    class Bird extends AnimalFly {
        public function fly() {}
    }

Otra solución consiste en implementar interfaces, por ejemplo Flyable y Runnable.

Reto D:
Problema:
Rompe el principio de segregación de interfaces (I) dado que la clase Consultant está obligada a implementar el método collate() el cual no necesita.
Solución:
Mover la definición del método collate de la interfaz UnderlingInterface a una nueva interfaz, por ejemplo, CollateInterface. Luego hacer que la clase Consultant implemente sólo UnderlingInterface y que la clase Underling implemente ambas interfaces. La clase Lumbergh queda igual.

    interface UnderlingInterface {
        public function program();
        public function filetps();
    }

    interface CollateInterface {
        public function collate();
    }

    class Underling implements UnderlingInterface, CollateInterface {
        public function program() {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }
        public function filetps() {
            return 'Place cover sheet on TPS report before going out';
        }
        public function collate() {
            return 'Collect and combine texts, information, and figures in proper order.';
        }
    }

    class Consultant implements UnderlingInterface {
        public function program() {
            return 'Outsource task to India';
        }
        public function filetps() {
            return 'Place cover sheet on TPS report before going out';
        }
    }

Reto E:
Problema:
Rompe el principio D.
Solución:
El módulo ContadorDeManzanas debería delegar la tarea de contar manzanas a la clase Manzano.

    class Manzano {
        private $manzanas = [];
        public function getManzanas() {
            return $this->manzanas;
        }
        public function cuentas() {
            return count($this->manzano->getManzanas());
        }
    }

    class ContadorDeManzanas {
        private $manzano;
        public function __contsruct(Manzano $manzano) {
            $this->manzano = $manzano;
        }
        public function cuantas() {
            return $this->manzano->cuentas();
        }
    }

resumen patatero, la inversion de dependencias , propone el uso de relaciones de composicion, es decir que un objeto este compuesto por otros objetos, pero que los elementos que lo componen no sea construidos en el objeto principal, en su lugar se deben recibir como parametros, para mas facilidad pensarlo como una fabrica de ensamblado que recibe piezas y con las piezas arma algo nuevo y mucho mas funcional

Muy interesante el planteamiento que menciona que los parametros del constructor no deben ser clases si no interfaces. Efectivamente es la forma correcta de hacerlo.

Este código no cumple con el principio de inyección de dependencias

class Notifier {
    lateinit var emailSender : EmailSender
    lateinit var messageSender: MessageSender
   constructor(){
    emailSender = EmailSender()
    messageSender = MessageSender()
  }   
}

Un punto importante es que EmailSender, MessageSender no deben de ser clases sino interfaces.

class Notifier {
  constructor(emailSender : EmailSender, messageSender: MessageSender) {
    this.emailSender = emailSender
    this.messageSender = MessageSender
  }
}

Al implementarlas como interfaces permitiría incluir tipos de servidores de correos como hotmail, gmail etc., además de incluir los mensajes de facebook, whatsapp, telegram, etc.,

interface EmailSender {
  fun sendEmail(message : String)
}

class Hotmail : EmailSender {
  overrider fun sendEmail(message : String)
}

class Gmail : EmailSender {
  overrider fun sendEmail(message : String)
}
interface MessageSender{
 fun sendMessage(message : String)
}

class WhatsApp : MessageSender{
  override fun sendMessage(message : String)
}
class Telegram : MessageSender{
  override fun sendMessage(message : String)
}```

Reto E: No respeta el principio de Inversión de Dependencias al no recibir un Interfaz sino un tipo de clase en concreto en el constructor. Puede abstraerse el contador de manzanos para cualquier otro fruto. El contador de frutos es un módulo de alto nivel que no depende de los detalles.

interface IProduccion
  {
      public function get()
  }

  class Manzano implements IProduccion
  {
      private $manzanas = [];

      public function get()
      {
          return $this->manzanas;
      }
  }

  class ContadorDeFrutas
  {
      public function __construct(IProduccion $arbol)
      {
          $this->arbol = $arbol;
      }

      public function cuantas()
      {
          return count($this->arbol->get());
      }
  }
 interface FlyingAnimal
    {
        public function fly();
    }

    class Animal implements FlyingAnimal
    {
        public function __construct( bool $hasWings ){
            $this->hasWings = $hasWings;
        }
    }

    class Dog extends Animal
    {
        public function fly()
        {
            if (! $this->hasWings) {
                throw new Exception;
            }
        }
    }

Si no estoy mal en este principio se aplica la “Inyeccion de Dependencias”

En el reto4d apliqué el principio de Liskov donde basicamente especialicé las interfaces para hacerlas más finas y no tener que imponerles a las clases que las implementen que también implementen todos sus métodos:

<?php

    interface UnderlingInterface {
        public function program();
        public function filetps();
        public function collate();
    }
    
    interface ConsultantInterface {
        public function program();
        public function filetps();
    }

    class Underling implements UnderlingInterface {
        public function program() {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps() {
            return 'Place cover sheet on TPS report before going out';
        }

    }

    class Consultant implements ConsultantInterface {
        public function program() {
            return 'Outsource task to India';
        }

        public function filetps() {
            return 'Place cover sheet on TPS report before going out';
        }

    }

?>```

Reto4b

<?php
    interface Workable
    {
      public function process();
    }

    class Programmer implements Workable
    {
        public function code()
        {
            return 'coding';
        }

        public function process()
        {
          $this->code();
        }
    }

    class Tester implements Workable
    {
        public function test()
        {
            return 'testing';
        }

        public function process()
        {
          $this->test();
        }
        
    }

    class ProjectManagement
    {
        public function process(Workable $member)
        {
            $member->process();
        }
    }

Reto4

<?php
    class Order {
        public function printOrder(){/*...*/}
        public function showOrder(){/*...*/}
    }

    class OrderItems {
        public function calculateTotalSum(){/*...*/}
        public function getItems(){/*...*/}
        public function getItemCount(){/*...*/}
        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}
    }

    interface OrderRecord {
        public function load(){/*...*/}
        public function save(){/*...*/}
        public function update(){/*...*/}
        public function delete(){/*...*/}
    }

Se puede complementar la informacion de SOLID: https://www.youtube.com/watch?v=2X50sKeBAcQ

```js interface Workable{ public function work(); } class Programmer implements Workable { public function work(){ return 'I am coding'; } } class Tester implements Workable { public function work(){ return 'I am tesing'; } } class ProjectManagement { public function process(Workable $member) { $member->work(); } } ```Comparto aqui uno
Estos retos fueron incluidos en la clase 10. Ahora, a la luz de los principios SOLID tenemos: **Reto4.php** Violación al principio de Responsabilidad única (S) ya que la clase maneja orden en los datos, gestiona items (getItems, etc) y maneja soporte de datos a disco (load, save, etc). **Reto4b.php** Violación al principio de Abierto/cerrado (O) ya que de adicionar soporte para una nueva clase diferente a Programmer y Tester, requiere modificar la clase ProjectManagement. Programmer y Tester podrían estar definidas por una interfaz con un método común para facilitar su uso en ProjectManagement (y evitar el `thrown Exception`). **Reto4c.php** Violación al principio de sustitución de Liskov ya que el método fly() definido en el padre se comporta diferente en la clase Dog. **Reto4d.php** Violación al principio de segregación de interfaz porque el método collapse() aparentemente no tiene implementación valida en la clase "Consultant" (a menos que en el contexto de la solución un valor de *null* fuera valido). **Reto4e.php** Violación al principio de inversión de dependencias, la clase Manzano debe proveer la información necesaria a "ContadorManzanas", por ello "Manzano" debería contener directamente un método cuantas() y n requerir que "ContadorManzanas" tenga que descargar (duplicar) la propiedad `manzanas`.

Claramente los principios SOLID, es una práctica que no suele estar presente en muchísimos programas de software que hoy en día corren en la internet. Sin embargo, podemos utilizar esta enseñanza y aplicarlo a cada uno de nuestros proyectos personales y en las empresas en la que trabajemos podemos proponer estas prácticas en caso de que no exista.

Principio de inversión de dependencias (DIP): Este principio establece que las dependencias deben ser inyectadas en las clases, en lugar de ser creadas por las clases. Esto hace que el código sea más flexible y fácil de probar

Principio de inversión de dependencias (DIP): Este principio establece que las dependencias deben ser inyectadas en las clases, en lugar de ser creadas por las clases. Esto hace que el código sea más flexible y fácil de probar.

🍃El Dependency Inversion Principle (Principio de Inversión de Dependencias) es uno de los cinco principios SOLID de programación orientada a objetos. Este principio establece que los módulos de alto nivel no deben depender directamente de los módulos de bajo nivel, sino que deben depender de abstracciones.

En otras palabras, las clases de nivel superior deben depender de interfaces o clases abstractas, en lugar de depender de las clases concretas de nivel inferior. Esto permite que los módulos de alto nivel no estén acoplados directamente a los módulos de bajo nivel, lo que permite una mayor flexibilidad y facilidad de mantenimiento.

El principio de inversión de dependencias se puede implementar utilizando la inyección de dependencias, que es una técnica de programación en la que una clase recibe sus dependencias externas en lugar de crearlas internamente. La inyección de dependencias se puede realizar de varias maneras, incluyendo la inyección por constructor, la inyección por propiedad y la inyección por método.

Al utilizar la inyección de dependencias, una clase de nivel superior no necesita conocer la implementación concreta de una clase de nivel inferior, sino que simplemente necesita una interfaz o clase abstracta que defina su comportamiento. Esto hace que el código sea más flexible, ya que se pueden intercambiar las implementaciones concretas de una clase de nivel inferior sin afectar el comportamiento de la clase de nivel superior.

Por ejemplo, si tuviéramos una clase ReportGenerator que depende directamente de la clase concreta DatabaseConnection, podríamos invertir la dependencia haciendo que la clase ReportGenerator dependa de una interfaz DatabaseInterface. De esta manera, podemos proporcionar diferentes implementaciones de la interfaz DatabaseInterface (por ejemplo, una implementación para una base de datos relacional y otra para una base de datos no relacional) sin tener que modificar la clase ReportGenerator.

En resumen, el principio de inversión de dependencias es importante porque permite una mayor flexibilidad y facilidad de mantenimiento al separar los módulos de alto nivel de los módulos de bajo nivel y permitir la inyección de dependencias en lugar de la creación de dependencias internamente. Esto hace que el código sea más modular, fácil de entender y mantener.

Reto 4e
Problema: No se cumple el Principio de Inversión de Dependencias ya que el constructor recibe una clase y no una interface.

    interface ManzanoInterface
    {
        public function getManzanas();
    }

    class Manzano implements ManzanoInterfacte
    {
        private $manzanas = [];

        public function getManzanas()
        {
            return $this->manzanas;
        }
    }


    class ContadorDeManzanas
    {
        private $manzano;

        public function __contsruct(ManzanoInterfacte $manzano)
        {
            $this->manzano = $manzano;
        }

        public function cuantas()
        {
            return count($this->manzano->getManzanas());
        }
    }

Reto 4d
Problema: No se cumple el Principio de Segregación de Interfaces, pues la clase Consultant está implementando el método collate() que no necesita y está devolviendo siempre un valor nulo.
Solución: La propuesta sería dividir la interface UnderlingInterface en dos interfaces según sus actividades y crear un método que agrupe las actividades que realiza cada uno, para que la clase Lumbergh pueda recibir la interface y llamar a este método.

    interface UnderlingInterface 
    {
        public function program();
        public function filetps();
        public function work();
    }

    interface CollateInterface 
    {
        public function collate();
    }

    class Underling implements UnderlingInterface, CollateInterface
    {
        public function program()
        {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function collate()
        {
            return 'Collect and combine texts, information, and figures in proper order.';
        }

        public function work()
        {
            $this->program();
            $this->filetps();
            $this->collate();
        }
    }

    class Consultant implements UnderlingInterface
    {
        public function program()
        {
            return 'Outsource task to India';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function work()
        {
            $this->program();
            $this->filetps();
        }
    }

    class Lumbergh
    {
        protected $underling;

        public function __construct(UnderlingInterface $underling)
        {
            $this->underling = $underling;
        }

        public function harass()
        {
            $this->underling->work();
        }
    }

Reto 4c
Problema: No se cumple el Principio de Sustitución de Liskov pues la clase hija está sobreescribiendo un método de la clase padre y altera su comportamiento pues arroja una excepción diferente.
Solución: La propuesta sería modificar la relación de herencia e implementar una interface para incluir el método fly(), de modo que no le imponemos a la clase Dog que implemente métodos que no le pertecen.

    interface Bird 
    {
        public function fly() 
        {
            return 'flying';
        };
    }

    class Animal
    {
    }

    class Dog extends Animal 
    {
    }

    class Eagle extends Animal implements Bird 
    {
    }

Reto 4b
Problema: No se cumple el Principio Abierto/Cerrado, porque si existieran más roles de empleados se tendría que modificar el método process() en la clase. ProjectManagement para agregar un nuevo caso.
Solución: La propuesta sería crear un método process() en cada una de las clases.

    class Programmer
    {
        public function process()
        {
            return 'coding';
        }
    }

    class Tester
    {
        public function process()
        {
            return 'testing';
        }
    }

    class ProjectManagement
    {
        public function process($member)
        {
            $member->process();
        }
    }

Reto 4
Problema: No se cumple el Principio de Responsabilidad Única, ya que hay una sola clase que hace muchas cosas, es un “hombre orquesta”.
Solución: La propuesta sería agrupar los métodos en nuevas clases.
Los métodos load, save, update y delete seguramente se podrían reutilizar y aplicar en otro contexto.

    class Order 
    {
        public function calculateTotalSum(){/*...*/}
    }

    class OrderItem
    {
        public function getItems(){/*...*/}
        public function getItemCount(){/*...*/}
        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}
    }

    class OrderPrint 
    {
        public function printOrder(){/*...*/}
    }

    class OrderShow 
    {
        public function showOrder(){/*...*/}
    }

    class DatabaseOperation 
    {
        public function load(){/*...*/}
        public function save(){/*...*/}
        public function update(){/*...*/}
        public function delete(){/*...*/}
    }
<?php

    interface employee {
        public function work();
    }

    class Programmer implements employee
    {
        public function work()
        {
            return 'coding';
        }
    }
    class Tester implements employee
    {
        public function work()
        {
            return 'testing';
        }
    }
    class ProjectManagement
    {
        public function process(employee $member)
        {
            return $member->work();
        }
    }

$manager = new ProjectManagement();
$tester = new Tester();
$programmer = new Programmer();

echo $manager->process($tester);
echo $manager->process($programmer);

<?php
    class Animal
    {
        public function fly()
        {
        }
    }

    class Canine
    {
        public function bark()
        {
            //
        }
    }

    class Dog extends Canine
    {
        public function bark()
        {
        return "Gruauf!";
        }
    }
<?php
class Order
{
    public function printOrder()
    { /*...*/
    }
    public function showOrder()
    { /*...*/
    }
}

class Calculations
{
    public function calculateTotalSum()
    { /*...*/
    }
}

class ManageCalculations
{
    public function load()
    { /*...*/
    }
    public function save()
    { /*...*/
    }
    public function update()
    { /*...*/
    }
    public function delete()
    { /*...*/
    }
}

class Items
{

    public function getItems()
    { /*...*/
    }
    public function getItemCount()
    { /*...*/
    }
    public function addItem($item)
    { /*...*/
    }
    public function deleteItem($item)
    { /*...*/
    }
}
<?php

    interface UnderlingInterface
    {
        public function program();

        public function filetps();

        public function collate();
    }

    interface ConsultantInterface
    {
        public function program();

        public function filetps();
    }

    class Underling implements UnderlingInterface
    {
        public function program()
        {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function collate()
        {
            return 'Collect and combine texts, information, and figures in proper order.';
        }
    }

    class Consultant implements ConsultantInterface
    {
        public function program()
        {
            return 'Outsource task to India';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }
    }

    class Lumbergh
    {
        protected $underling;

        public function __construct(UnderlingInterface $underling)
        {
            $this->underling = $underling;
        }

        public function harass()
        {
            $this->underling->program();
            $this->underling->filetps();
            $this->underling->collate();
        }
    }

reto4.php

<?php

    class Item {
        public function calculateTotalSum(){/*...*/}
        public function getItems(){/*...*/}
        public function getItemCount(){/*...*/}
        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}
    }

    class Order {
        public function printOrder(){/*...*/}
        public function showOrder(){/*...*/}
    }

    class Database {
        public function load(){/*...*/}
        public function save(){/*...*/}
        public function update(){/*...*/}
        public function delete(){/*...*/}
    }

reto4b.php

<?php
    interface Codeable {
        public function code();
    }

    interface Testable {
        public function test();
    }

    class Programmer implements Codeable
    {
        public function code()
        {
            return 'coding';
        }
    }
    
    class Tester implements Testable
    {
        public function test()
        {
            return 'testing';
        }
    }

    class ProjectManagement
    {
        public function process($member)
        {
            if ($member instanceof Codeable) {
                $member->code();
            } elseif ($member instanceof Testable) {
                $member->test();
            };
            throw new Exception('Invalid input member');
        }
    }

reto4c.php

<?php
    class Animal {
        // ...
    }
    
    class FlyingAnimal extends Animal
    {
        public function fly()
        {
        }
    }

    class Dog extends Animal
    {
        public function fly()
        {
            if (! $this->hasWings) {
                throw new Exception;
            }
        }
    }

reto4d.php

<?php

    interface BaseInterface {
        public function program();
        public function filetps();
    }

    interface UnderlingInterface {
        public function collate();
    }

    class Base {
        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }
    }

    class Underling extends Base implements BaseInterface, UnderlingInterface
    {
        public function program()
        {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }
        
        public function collate()
        {
            return 'Collect and combine texts, information, and figures in proper order.';
        }
    }

    class Consultant extends Base implements BaseInterface
    {
        public function program()
        {
            return 'Outsource task to India';
        }
    }

    class Lumbergh
    {
        protected $underling;

        public function __construct(Underling $underling)
        {
            $this->underling = $underling;
        }

        public function harass()
        {
            $this->underling->program();
            $this->underling->filetps();
            $this->underling->collate();
        }
    }

reto4e.php

<?php
    interface ManzanoInterface {
        public function getManzanas();
    }

    class Manzano implements ManzanoInterface
    {
        private $manzanas = [];

        public function getManzanas()
        {
            return $this->manzanas;
        }
    }

    class ContadorDeManzanas
    {
        private $manzano;

        public function __contsruct(ManzanoInterface $manzano)
        {
            $this->manzano = $manzano;
        }

        public function cuantas()
        {
            return count($this->manzano->getManzanas());
        }
    }

Esto me lo preguntaron en una entrevista, vine acá a aprenderlo, gracias!

Básicamente se trata de reducir la cantidad de dependencias que tiene una clase de alto nivel de las clases de bajo nivel, aunque en este ejemplo se está violando el principio de abierto cerrado, pues si surge una nueva clase de notificación habría que modificar los parámetros del constructor para agregarlo…

el esfuerzo por explicar los principios SOLID es algo que se valora, sin embargo, hay partes en las que si bien lo trata de explicar no queda del todo claro, de modo que dejare esto por aqui si quieren tener una mayor claridad o un refuerzo al concepto que se expone:
https://www.youtube.com/watch?v=2X50sKeBAcQ

Reto 4d

Creo que esta violando el Interface Segregation Principle ya que en la clase consultant esta apareciendo un metodo que da como resultado un null, ya que no la necesita.

Mi solución

interface UnderlingInterface
    {
        public function program();
        public function filetps();
    }

    interface CollateInterface {
        public function collate();
    }

    class Underling implements underlingInterface, CollateInterface
    {
        public function program()
        {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function collate()
        {
            return 'Collect and combine texts, information, and figures in proper order.';
        }
    }

    class Consultant implements UnderlingInterface
    {
        public function program()
        {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }
    }

No supe como solucionar esta parte

class Lumbergh
    {
        protected $underling;

        public function __construct(UnderlingInterface $underling)
        {
            $this->underling = $underling;
        }

    }

Reto 4c

VIOLA - Liskov Substitution Principle y Interface Segregation Principle

La clase dog al heredar de la clase animal, se ve obligado a implementar el metodo fly, ya que la logica del negocio nos dice que un perro no puede volar, bueno hasta ahora no hay un caso en la vida real xD

interface CanFly
    {
        
        public function fly();
    }

    class Animal
    {
        
    }

    class Dog implements Animal
    {
        public function bark()
        {
            echo 'The dog is Barking';
        }
    }

    class Bird implements Animal, CanFly
    {
        private $haswings;
        public function fly()
        {
            echo "The Bird is Flying";
        }
    }

Reto 4b

violando asi el principio Open/closed principle.

La clase Project management, al parecer es una solución a corto plazo a la que necesita para que cumpla su objetivo, el problema viene cuando queremos expandir más adelante esta funcionalidad, ya que necesitamos modificar el codigo que funciona para que estas futuras funcionalidades se acoplen al código actual.

Mi Solución

interface ProcessInterface 
    {
        public function process();
    }


    class Programmer implements ProcessInterface
    {
        public function code()
        {
            return 'coding';
        }

        public function process()
        {
            return 'process';
        }
    }
    class Tester implements ProcessInterface
    {
        public function test()
        {
            return 'testing';
        }

        public function process()
        {
            return 'process';
        }
    }

    class ProjectManagement
    {
        public function process(ProcessInterface $processInterface)
        {
            $processInterface->process();
        }
    }

Reto 4

Viola Single Responsibility Principle
La clase Order tienen metodos que son necesarias para que funcione la clase pero esos metodos están desviando su objetivo principal que es manejar solo orders.

Mi solución

class Order
{
    public function calculateTotalSum(){/*...*/}
    public function getItems(){/*...*/}
    public function getItemCount(){/*...*/}
    public function addItem($item){/*...*/}
    public function deleteItem($item){/*...*/}

    public function printOrder(){/*...*/}
    public function showOrder(){/*...*/}
}

class Database 
{
    public function load(){/*...*/}
    public function save(){/*...*/}
    public function update(){/*...*/}
    public function delete(){/*...*/}
}

Reto4b: Liskov Substitution Principle

Reto4d: Interface Segregation Principle

Reto4: Single Responsibility Principle

Reto4c: Liskov Substitution Principle

Reto4e: No supe cual era

Creo que si creamos una abstracción llamada Sender que pudiera ser implementada (o heredada) en los Senders concretos como el EmailSender, WhatsappSender, etc y en la clase Notifier usar un arreglo de Senders podría incluso extraerse más el comportamiento.

En caso de que el notificador no fuera único y existieran varias formas de implementarlo también abogaría por la abstracción y generación de notificadores concretos.

Este principio es genial y la puerta para entender muchos patrones de diseño.

en reto4.php no parece que se respete el principio de responsabilidad Unica
en reto4b.php se puede mejorar siguiendo el principio de abierto/cerrado
en reto4c.php no encontre mejoras o principios que no se respeten
en reto4d.php puede mejorar si se respetara el principio de segregacion de interfaces
en reto4e.php no veo mejoras, de hecho creo que respeta el principio de inversion de dependencias

Esta… realmente no entendí muy bien lo que tenía que hacer pero por mejorar el código…

<?php
    class Animal
    {

    }

    class Dog extends Animal
    {
        public function bark()
        {
            return "Woof!";
        }
    }

    class Bird extends Animal
    {
        public function fly()
        {
            return "I'm flying!";
        }
    }

Principio SOLID: Single Responsability Principle

Apunta a desarrollar aplicaciones mas mantenibles a través del tiempo

S: Single Responsibility Principle (SRP) Una sola razón para cambiar

O: Open/Closed Principle (OCP) Abierta para su extensión, cerrada para modificación

L: Liskov Substitution Principle (LSP) Usar métodos clase padre solamente , la clase hijo no debe alterar el comportamiento de los métodos del padre

I: Interface Segregation Principle (ISP) Los clientes de un programa solo deben conocer los métodos que usan

D: Dependency Inversion Principle (DIP) Los modulos de alto nivel no deben depender de los de bajo nivel.

Las abstracciones no deben depender de los detalles, los detalles deben depender de las abstracciones.

Este informacion le podria ayudar a mas de uno 😊
https://gustavopeiretti.com/principios-solid-con-ejemplos/

4/5 retos que pude identificar he intentar solucionar.

Single Reponsibility Principle

    class Order
    {
        public function printOrder(){/*...*/}
        public function showOrder(){/*...*/}
    }

    class Item  
    {
        public function getItems(){/*...*/}
        public function getItemCount(){/*...*/}

        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}   
    }

    class Calculate  
    {
        public function calculateTotalSum(){/*...*/}
    }

    class DataBase  
    {
        public function load(){/*...*/}
        public function save(){/*...*/}
        public function update(){/*...*/}
        public function delete(){/*...*/}
    }

Open/Closed Principle

interface ProcessInterface 
    {
        public function process($member);
    }
    
    class ProjectManagement
    {
        public function process($member)
        {
            $member->process($member);
        }
    }

    class Programmer implements ProcessInterface
    {
        public function code()
        {
            return 'coding';
        }

        public function process($member)
        {
            $member->code();
        }
    }

    class Tester implements ProcessInterface
    {
        public function test()
        {
            return 'testing';
        }

        public function process($member)
        {
            $member->test();
        }
    }

Liskov Substitution Principle

class Animal
    {
        public function fly()
        {
            if (! $this->hasWings) {
                throw new Exception;
            }
        }
    }

    class Dog extends Animal
    {
        
    }

Interface Segregation Principle

interface UnderlingInterface
    {
        public function program();

        public function filetps();
    }

    interface ConsultantInterface 
    {
        public function collate();
    }


    class Underling implements UnderlingInterface, ConsultantInterface
    {
        public function program()
        {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function collate()
        {
            return 'Collect and combine texts, information, and figures in proper order.';
        }
    }

    class Consultant implements UnderlingInterface
    {
        public function program()
        {
            return 'Outsource task to India';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }
    }

    class Lumbergh
    {
        protected $underling;

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

        public function harass()
        {
            $this->underling->program();
            $this->underling->filetps();
            $this->underling->collate();
        }
    }

Esto es lo que hice sobre el ejercicio de DIP

<?php
    class Arbol
    {
        private $tipoFruto; 
        private $frutos = [];

        public function getFrutos()
        {
            return $this->frutos;
        }
    }

    class ContadorDeFrutoa
    {
        private $Arbol;

        public function __contsruct(Arbol $Arbol)
        {
            $this->Arbol = $Arbol;
        }

        public function cuantas()
        {
            return count($this->frutos->getFrutos());
        }
    }
?>

“En algún momento nuestro programa o aplicación llegará a estar formado por muchos módulos. Cuando esto pase, es cuando debemos usar inyección de dependencias, lo que nos permitirá controlar las funcionalidades desde un sitio concreto en vez de tenerlas esparcidas por todo el programa. Además, este aislamiento nos permitirá realizar testing mucho más fácilmente.”

fuente:https://enmilocalfunciona.io/principios-solid/

My python implementation for challenge reto4b:

"""Open/Closed principle"""

import abc


class Workable(abc.ABC):
    """"""

    @abc.abstractmethod
    def process(self):
        """"""


class Programmer(Workable):

    def code(self):
        """"""
        return 'coding'

    def process(self):
        """"""
        self.code()


class Tester(Workable):

    def test(self):
        """"""
        return 'testing'

    def process(self):
        """"""
        self.test()


class ProjectManagement:
    """"""

    def process(self, member: Workable):
        """"""
        member.process()

My python implementation for challenge reto4c:

"""Liskov substitution principle"""

import abc


class Flyable(abc.ABC):
    """"""

    @abc.abstractmethod
    def fly(self):
        """"""


class Animal:
    """"""

    def eat(self):
        """"""


class Dog(Animal):
    """"""

    def eat(self):
        """"""
        return 'eat meat'


class Bird(Animal, Flyable):

    def eat(self):
        """"""
        return 'eat earthworms'

    def fly(self):
        """"""
        return 'Birds fly in different directions'


def animal_eat(animal: Animal):
    animal.eat()


Según mi punto de vista el archivo que infringía uno de los principios SOLID es el archivo reto4.php
Aquí esta resuelto:

<?php
    class TotalOrder {
        public function calculateTotalSum(){/*...*/}
    }
    class OrderItems{
        public function getItemCount(){/*...*/}
        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}
        public function getItems(){/*...*/}
    }
    class OrderActions{
        public function printOrder(){/*...*/}
        public function showOrder(){/*...*/}
    }
    class OrderStates{
        public function load(){/*...*/}
        public function save(){/*...*/}
        public function update(){/*...*/}
        public function delete(){/*...*/}
    }
?>

El “ Principio de inversión de dependencia establece que la política de alto nivel de su sistema no debe depender de detalles de bajo nivel. Además, las abstracciones nunca deberían depender de los detalles. Los singleton suelen implementar algunos detalles de bajo nivel

FALTAN ARCHIVOS DEL RESTO

La Inversion de Dependencia o Dependecy Inversion, tambien hace parte de IoC (Inversion de Control o Inversion of Control)

No se encuentran los retos de los que habla Mauro en el vídeo, creen que podrían agregarlos?

Una pregunta para confirmar si he entendido bien, Para llevar a cabo la utilizacion de este principio, tendríamos que modificar también la instancia que creamos del notificador? para enviarle las nuevas clases al constructor nuevo?

no hay … 😕

En el reto4 lo conveniente sería implementar nuevas clases para que por ejemplo: load(), save() y upload() se encuentren en una clase diferente a las demás funciones y no dejar caer el toda la responsabilidad en la clase existente.

reto4e

<?php
    interface ManzanoInterface
    {
      public function getManzanas();
    }

    class Manzano implements ManzanoInterface
    {
        private $manzanas = [];

        public function getManzanas()
        {
            return $this->manzanas;
        }
    }

    class ContadorDeManzanas
    {
        private $manzano;

        public function __construct(ManzanoInterface $manzano)
        {
            $this->manzano = $manzano;
        }

        public function cuantas()
        {
            return count($this->manzano->getManzanas());
        }
    }

Creo que estaría bueno que en cada desafío se plantee un problema que se quiere resolver, como la lógica de negocio. De manera que en base a eso podamos proponer una solución adecuada. De por ahi eso nos ayuda a estar más seguros de que la solución que encontremos sea la adecuada.

<?php
    class Order {
        public function calculateTotalSum(){/*...*/}
        public function getItems(){/*...*/}
        public function getItemCount(){/*...*/}
        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}

        public function printOrder(){/*...*/}
        public function showOrder(){/*...*/}

        
    }
    class manageOrder{
         function __construct() {
            print "En el constructor BaseClass\n";
         }
       	
	 public function load($order){/*...*/}
         public function save($order){/*...*/}
         public function update($order){/*...*/}
         public function delete($order){/*...*/}
    }
    

hice uno pero para kotlin


fun main() {
    val SAMSUNG : String = "samsung"
	val LG : String = "lg"
    val MOTOROLA : String = "motorola"
    
    var  motorolaCelular = Celular(MOTOROLA,"celular","G7",35000)
    var samsungTV = Televition(SAMSUNG,"television","RG85",15900)
    
    var itemsManager : ItemsManager = ItemsManager()
    itemsManager.addItem(samsungTV)
    itemsManager.addItem(motorolaCelular)
    
    println("total items: " + itemsManager.getItemCount())
    println("total price: $" + itemsManager.calculateTotalSum())
    
    print("TV Models: " )
    itemsManager.getItems().forEach{it ->         	
        	print(if(it.getType() == "television")it.getModel() else "")
    }
    print("\nCelualars Models: " )
    itemsManager.getItems().forEach{it ->         	
        	print(if(it.getType() == "celular")it.getModel() else "")
    }
    
}
abstract class Item {
    private var brand : String = ""
    private var type : String = ""
    private var model : String = ""
    private var price : Int = 0
    
    constructor(brand:String, type:String, model:String, price:Int){
        this.type = type
        this.model = model
        this.price = price    
        this.brand = brand
    }
    fun getBrand() : String{
        return this.brand
    }
    
    fun getType() : String{
        return this.type
    }
    fun getModel() : String{
        return this.model
    }
    fun getPrice() : Int {
        return this.price
    }
}

class Celular : Item {
    constructor(brand:String, type:String,model:String, price: Int) : super(brand,type,model,price)       
}
class Televition : Item {
    constructor(brand:String,type:String,model:String, price: Int) : super(brand,type,model,price)    
    
}
class ItemsManager{  
    private var items : MutableList<Item>  = ArrayList<Item>()
	private var item : Item? = null 
    
    fun addItem(item : Item){
        items.add(item)
    }
    fun calculateTotalSum() : Int{
        var totalSum : Int = 0
        for(item in items){
            totalSum += item.getPrice()
        }
        return totalSum
    }
    fun getItems():List<Item>{
        return items
    }
    fun getItemCount():Int{
        return items.size
    }       
}

Clase 14: Principio de segregación de interfaz
El Interface Segregation Principle establece que los clientes de un programa dado sólo deberían conocer de éste los métodos que realmente usan.
Nota: este principio dice como estructurar las interfaces. De modo que cuando una clase implementa una interface no se le exija implementar métodos que no necesita o no son propios.
Clase 15: Principio de inversión de dependencia
Dependency Inversion Principle detalla que los módulos de alto nivel no deben depender de los de bajo nivel, ambos deben depender de abstracciones.
Las abstracciones no deben depender de los detalles, los detalles deben depender de las abstracciones.

Nota: este principio nos ayuda a definir como se vinculan las diferentes clases con que tienen que darle servicios a otras, ya que tenemos clases de alto nivel y bajo nivel. Las de alto nivel son las que tienen la lógica del negocio y las de bajo nivel

Reto4

	//SOLID - SRP

	//Dedicada a Operaciones de Calculo
    class CalculateOrder
    {
        public function calculateTotalSum(){/*...*/}
        public function getItems(){/*...*/}
        public function getItemCount(){/*...*/}
        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}
    }

	//Dedicada a Despliegue de Información
    class DisplayOrder
    {
        public function printOrder(){/*...*/}
        public function showOrder(){/*...*/}
    }

	//Dedicada a Operaciones de Almacenamiento
    class PersistenceOrder
    {
        public function load(){/*...*/}
        public function save(){/*...*/}
        public function update(){/*...*/}
        public function delete(){/*...*/}
    }

Reto4d

//SOLID - ISP
    interface WorkerInterface
    {
        public function work();
    }

    interface ConsultantInterface extends WorkerInterface
    {
        public function program();

        public function filetps();
    }

    interface UnderlingInterface extends ConsultantInterface
    {
        public function collate();
    }

    class Underling  implements UnderlingInterface
    {
        public function program()
        {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function collate()
        {
            return 'Collect and combine texts, information, and figures in proper order.';
        }
		
        public function work()
        {
            program();
			filetps();
			collate();
        }
    }

    class Consultant implements ConsultantInterface
    {
        public function program()
        {
            return 'Outsource task to India';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function work()
        {
            program();
			filetps();
        }
    }

    class Lumbergh
    {
        protected $underling;

        public function __construct(UnderlingInterface $underling)
        {
            $this->underling = $underling;
        }

        public function harass()
        {
            $this->underling->work();
        }
    }

SOLID: Dependency Inversion Principle
Detalla que los modulos de alto nivel no deben depender de los de bajo nivel, ambos deben depender de abstracciones.
Las abrastracciones no deben depender de los detalles, los detalles deben depender de las abstracciones

Ya había escuchado y “aprendido” los principios SOLID, pero con estas clases me ha quedado más claro.

interface IManzano
    {
        public function getManzanas()
    }

    class Manzano implements IManzano
    {
        private $manzanas = [];

        public function getManzanas()
        {
            return $this->manzanas;
        }
    }

    class ContadorDeManzanas
    {
        public function __contsruct(IManzano $manzano)
        {
            $this->manzano = $manzano;
        }

        public function cuantas()
        {
            return count($this->manzano->getManzanas());
        }
    }
    class ManageOrder
    {
        public function calculateTotalSum(){/*...*/}
        public function getItems(){/*...*/}
        public function getItemCount(){/*...*/}
        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}
    }

    class OrderData{
        public function load(){/*...*/}
        public function save(){/*...*/}
        public function update(){/*...*/}
        public function delete(){/*...*/}

    }


    class Order{
        public function printOrder(){/*...*/}
        public function showOrder(){/*...*/}
    }
interface UnderlingInterface
    {
        public function program();
        public function filetps();
        public function collate();
    }

    interface ConsultantInterface{
        public function program();
        public function filetps();
    }




    class Underling implements UnderlingInterface
    {
        public function program()
        {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function collate()
        {
            return 'Collect and combine texts, information, and figures in proper order.';
        }
    }




    class Consultant implements ConsultantInterface
    {
        public function program()
        {
            return 'Outsource task to India';
        }

        public function filetps()
        {
            return 'Place cover sheet on TPS report before going out';
        }

        public function collate()
        {
            return null;
        }
    }




    class Lumbergh
    {
        protected $underling;

        public function __construct(UnderlingInterface $underling)
        {
            $this->underling = $underling;
        }

        public function harass()
        {
            $this->underling->program();
            $this->underling->filetps();
            $this->underling->collate();
        }
    }

los parámetros que recibe el constructor deben ser interfaces

El principio sería como un ejemplo así:

class Numbers {
    constructor(num1, num2) {
        this.num1 = num1
        this.num2 = num2
    }
}


class Sum extends Numbers {
    constructor(num1, num2) {
        super(num1, num2)
    }
    sum() {
        return console.log(this.num1 + this.num2);
    }
}

class Mult extends Numbers {
    constructor(num1, num2) {
        super(num1, num2)
    }
    mult() {
        return console.log(this.num1 * this.num2);
    }
}
const sum = new Sum(2, 4);
sum.sum();

const mult = new Mult(3, 4);
mult.mult();

por lo que veo solo la interfaz EmailSender podria implementarse ya que puede ser mediante hotmail, gmail, etc ya que la de WhatsApp no esta bien, creo que seria hacer una interfaz superior en la que se pudeira incluir whatsapp, facebook, telegram etc.

Esto es muy interesante en verdad sigo epnsando que esto es practucamente implementar patrones de diseño.

Reto A: En este use el single responsability

<?php
    //Single responsability

  class OrderCRUDE  {
    public function load(){ /*  */}
    public function save(){ /*  */}
    public function update(){ /*  */}
    public function delete(){ /*  */}
  }

  class actionOrder {
    public function addItem($item){/*...*/}
    public function deleteItem($item){/*...*/}
    public function printOrder(){/*...*/}
    public function showOrder(){/*...*/}
    public function calculateTotalSum(){/*...*/}
  }

  class GetOrderItem {
    public function getItems(){/*...*/}
    public function getItemCount(){/*...*/}
  }

Reto4b

fun main() {
    val programer = Programmer()
    val tester = Tester()
    val projectManagement = ProjectManagement()
    val programmerDo = projectManagement.process(programer)
    val testerDo = projectManagement.process(tester)
    
    
    println("A programmer is " + programmerDo)
    println("A tester is " + testerDo)
}
interface Workable {
    fun process(): String
}
class Programmer : Workable {
    public fun code():String
    {
        return "coding"
    }
    override fun process() : String{
        return code()
    }
}

class Tester : Workable {
    public fun test() : String
    {
        return "testing"
    }
    override fun process(): String{
        return test()
    }
}
class ProjectManagement {
    
    public fun process( member : Workable): String
    {
        return member.process()
    }
}

Reto4c

<?php
    class Animal
    {
        public $hasWings;
    }

    class Bird extends Animal
    {
        public function fly()
        {
            if (! $this->hasWings) {
                throw new Exception;
            }
            return 'flying';
        }
    }

    class Dog extends Animal
    {
    }

reto4c



fun main() {
  val duke = Dog()
  val littleBird = Bird()
  var animalMoveManager =  AnimalMoveManager()
  animalMoveManager.move(duke)
  animalMoveManager.move(littleBird)
  
  animalMoveManager.move(duke,"duke")
  animalMoveManager.move(littleBird, "bird")
  
}
interface Flyable{
    public fun fly(name:String)
    
}
interface Animal{
    public fun walk(name:String)
}




class Dog : Animal
{
   private fun run(name:String){
       println(name + "is running!")
   }
   override fun walk(name:String)
    {
        run(name)
    }
}

class Bird : Animal, Flyable{
    override fun walk(name:String){
        println(name + " is moving!")        
    }
    override fun fly(name:String){
        println(name + " is flying")
    }
}

class AnimalMoveManager{
    public fun move( animal : Animal, name:String = "animal"){
        animal.walk(name)
    }
}

output

animalis running!
animal is moving!
dukeis running!
bird is moving!```

reto4d



fun main() {
 var consultant = Consultant()
 var lumberg = Lumbergh(consultant)
 lumberg.harass()
  
}

interface UnderlingInterface
    {
        public fun program() : String;

        public fun filetps() : String;

        public fun collate() : String;
    }

    class Underling : UnderlingInterface {
        override fun program() : String
        {
            return "Program initech systems to deposit fractions of pennies to private account";
        }

        override public fun filetps() : String
        {
            return "Place cover sheet on TPS report before going out";
        }

        override public fun collate() : String
        {
            return "Collect and combine texts, information, and figures in proper order.";
        }
    }

    class Consultant : UnderlingInterface
    {
        override public fun program() : String
        {
            return "Outsource task to India";
        }

        override public fun filetps() : String
        {
            return "Place cover sheet on TPS report before going out";
        }

        override public fun collate() : String
        {
            return "";
        }
    }

    class Lumbergh
    {
        var underling : UnderlingInterface

        constructor(underling : UnderlingInterface)
        {
            this.underling = underling;
        }

        public fun harass()
        {
            println(this.underling.program());
            println(this.underling.filetps());
            println(this.underling.collate());
        }
    }```

output


Outsource task to India
Place cover sheet on TPS report before going out


Perfecto. Gracias

Reto 1

<?php

    class Order {
        public function load(){/*...*/}
        public function save(){/*...*/}
        public function update(){/*...*/}
        public function delete(){/*...*/}
    }

    class OrderItemManager {
        public function calculateTotalSum(){/*...*/}
        public function getItems(){/*...*/}
        public function getItemCount(){/*...*/}
        public function addItem($item){/*...*/}
        public function deleteItem($item){/*...*/}
    }

    class OrderPrinter() {
        public function printOrder(){/*...*/}
        public function showOrder(){/*...*/}
    }

// class Order
// {
//     public function calculateTotalSum(){/*...*/}
//     public function getItems(){/*...*/}
//     public function getItemCount(){/*...*/}
//     public function addItem($item){/*...*/}
//     public function deleteItem($item){/*...*/}

//     public function printOrder(){/*...*/}
//     public function showOrder(){/*...*/}

//     public function load(){/*...*/}
//     public function save(){/*...*/}
//     public function update(){/*...*/}
//     public function delete(){/*...*/}
// }

Mi código del primer reto, en este caso apliqué el principio de sustitución de Liskov:

<?php
  
    class Worker() {
  
        public function do_what_you_can_do() {
            $this->work();
        }

    }

    class Programmer extends Worker
    {
        public function work()
        {
            return 'coding';
        }
    }
    class Tester extends Worker
    {
        public function work()
        {
            return 'testing';
        }
    }
    class ProjectManagement
    {
        public function process(Worker $member)
        {

            $member->do_what_you_can_do();
        }
    }

Reto 2

<?php
    class Programmer
    {   
        public function __construct() {
            return $this->code()
        }

        public function code()
        {
            return 'coding';
        }
    }

    class Tester
    {
        public function __construct() {
            return $this->test()
        }

        public function test()
        {
            return 'testing';
        }
    }

    class ProjectManager 
    {
        $MEMBER_LIST = array('Programmer', 'Tester')
        public function process($member)
        {
            for ($i = 0; i <= count($this->$MEMBER_LIST); $i++) {
                if (in_array($member, $this->$MEMBER_LIST)) {
                    $member()
                } else {
                    throw new Exception('Invalid input member');
                }
            }
        }
    }

Ejercicio E

    /* Dependency Inversion Principle */

    interface fruta 
    {
        public function getFruta();
    }

    class Manzana implements fruta
    {
        private $manzanas = [];
        public function getFruta()
        {
            return $this->manzanas;
        }
    }

    class Banano implements fruta
    {
        private $bananos = [];
        public function getFruta()
        {
            return $this->bananos;
        }
    }

    class ContadorDeFrutas
    {
        private $fruta;

        public function __contsruct(fruta $fruta)
        {
            $this->fruta = $fruta;
        }

        public function contar()
        {
            return count($this->fruta->getFruta());
        }
    }

    $bananos = new Banano();
    $contadorBananos = new ContadorDeFrutas($Bananos);
    $cantidad = $contadorBananos->contar();

    $manzanas = new Manzana();
    $contadorManzanas = new ContadorDeFrutas($manzanas);
    $cantidad = $contadorManzanas->contar();

Reto 4.

Interface Order
{
    public function calculateTotalSum();
}

Interface Items
{
    public function getItems();
    public function getItemCount();
    public function addItem($item);
    public function deleteItem($item);
}

Interface OrderRender
{
    public function printOrder();
    public function showOrder();
}

Interface OrderCrudActions
{
    public function load();
    public function save();
    public function update();
    public function delete();
}

class Order implements Order, OrderRender, OrderCrudActions
{
    protected $item; 

    public function __construct(Items $item)
    {
        $this->item = $item;
    }

    public function calculateTotalSum()
    {

    }
}

– Reto 4b.

class ProjectManagement
    {
        public function processCode(Programmer $member)
        {
            $member->code();
        }

        public function test(Tester $member)
        {
            $member->test();
        }
    }

– Reto 4c.

interface Animal
    {

    }

    class FlyingAnimal
    {
        public function fly(){}
    }

    class LandAnimal
    {

    }

– Reto 4d.

interface CollateInterface
    {
        public function collate();
    }

    interface ConsultantInterface
    {
        public function program();
        public function filetps();
    }

    interface UnderlingInterface extends CollateInterface, ConsultantInterface
    {

    }

    class Underling implements UnderlingInterface
    {
        public function program() {
            return 'Program initech systems to deposit fractions of pennies to private account';
        }

        public function filetps(){
            return 'Place cover sheet on TPS report before going out';
        }

        public function collate(){
            return 'Collect and combine texts, information, and figures in proper order.';
        }
    }

    class Consultant implements ConsultantInterface
    {
        public function program(){
            return 'Outsource task to India';
        }

        public function filetps(){
            return 'Place cover sheet on TPS report before going out';
        }
    }

    class Lumbergh
    {
        protected $underling;

        public function __construct(UnderlingInterface $underling){
            $this->underling = $underling;
        }

        public function harass(){
            $this->underling->program();
            $this->underling->filetps();
            $this->underling->collate();
        }
    }

– Reto 4e.

class Manzano
    {
        private $manzanas = [];

        public function getManzanas()
        {
            return $this->manzanas;
        }

        public function cuantas()
        {
            return count($this->manzanas);
        }
    }

Increíble, tiempo tratando de encontrarle utilidad y en el 3:39 lo encontré.

En este video de BetaTech explica los principios solid, me sirvio para reforzar el conocimiento de este curso.

https://architectcoders.com/wp-content/uploads/2019/08/principios-solid-devexperto.pdf

Conclusión:
“Como ves, este mecanismo nos obliga a organizar nuestro código de una manera
muy distinta a como estamos acostumbrados, y en contra de lo que la lógica
dicta inicialmente, pero a la larga compensa por la flexibilidad que otorga a la
arquitectura de nuestra aplicación”

Este era (hasta hoy) uno el principio que más me costaba entender.

Gracias che!! Toda una joya la explicación de los principios

My python implementation for challenge reto4 :

"""Single responsibility principle"""


class Order:

    def __init__(self):
        """"""

    def print_order(self, pk: int) -> None:
        """"""

    def show_order(self, pk: int) -> object:
        """"""

    def calculate_total_sum(self) -> float:
        """"""


class OrderItem:

    def __init__(self):
        """"""

    def add_item(self, item: object) -> object:
        """"""

    def get_item_count(self, pk: int) -> object:
        """"""

    def delete_item(self, pk: int) -> None:
        """"""

    def get_item(self, pk: int) -> object:
        """"""


class OrderRecord:

    def __init__(self):
        """"""

    def load(self, pk: int) -> object:
        """"""

    def save(self, order: object) -> object:
        """"""

    def update(self, order: object) -> object:
        """"""

    def delete(self, pk: int) -> object:
        """"""

**Reto4b **
Se aplicó Open/Closed principle ahora se puede agregar otras profesiones y clase ProyectManagement no se tendrá que modificar.

<?php
    interface IProfession{
        public function activity();
    }

    class Programmer implements IProfession
    {
        public function activity()
        {
            return 'coding';
        }
    }
    class Tester implements IProfession
    {
        public function activity()
        {
            return 'testing';
        }
    }

    //Open/Closed principle ahora se puede agregar otras profesiones y clase ProyectManagement no se tendrá que modificar
    class ProjectManagement
    {
        public function process(IProfession $member)
        {
            $member->activity();
        }
    }

reto4c
Se corrigió violación de Liskov Substitution Principle

<?php
// Se corrigió violación de Liskov Substitution Principle
interface IFly
{
    public function fly();
}

class Animal
{
}

class Dog extends Animal implements IFly
{
    public function fly()
    {
        if (!$this->hasWings) {
            throw new Exception;
        }
    }
}

reto4d
Se agregó Interface Segregation Principle para no forzar la implementación de todos los métodos

<?php
// se agregó Interface Segregation Principle para no forzar la implementación de todos los métodos
interface IProgram
{
    public function program();
}
interface IFiletps
{
    public function filetps();
}
interface ICollate
{
    public function collate();
}


class Underling implements IProgram, IFiletps, ICollate
{
    public function program()
    {
        return 'Program initech systems to deposit fractions of pennies to private account';
    }

    public function filetps()
    {
        return 'Place cover sheet on TPS report before going out';
    }

    public function collate()
    {
        return 'Collect and combine texts, information, and figures in proper order.';
    }
}

class Consultant implements IProgram, IFiletps
{
    public function program()
    {
        return 'Outsource task to India';
    }

    public function filetps()
    {
        return 'Place cover sheet on TPS report before going out';
    }
}

class Lumbergh
{
    protected $program;
    protected $filetps;
    protected $collate;

    public function __construct(IProgram $program, IFiletps $filetps, ICollate $collate)
    {
        $this->program = $program;
        $this->filetps = $filetps;
        $this->collate = $collate;
    }

    public function harass()
    {
        $this->program->program();
        $this->filetps->filetps();
        $this->collate->collate();
    }
}

reto4e
se aplicó Dependency Inversion Principle para desacoplar la clase de bajo nivel Manzano de la clase de alto nivel ContadorDeManzanas

<?php
// se aplicó Dependency Inversion Principle para desacoplar la clase de bajo nivel Manzano de la clase de alto nivel ContadorDeManzanas 
interface ITree
{
    public function getFruits();
}

class Manzano implements ITree
{
    private $manzanas = [];

    public function getFruits()
    {
        return $this->manzanas;
    }
}

class ContadorDeFrutas
{
    private $tree;

    public function __contsruct(ITree $tree)
    {
        $this->tree = $tree;
    }

    public function cuantas()
    {
        return count($this->tree->getFruits());
    }
}

Estoy bastante perdido en este tema de los principios solid. Entiendo lo que quiere decir pero al momento de inspeccionar los códigos brindados es que como que estoy ciego y no puedo ver nada. Pero bueno supongo que será seguir practicando y repetir algunas clases para digerir mejor el contenido. 🙂

<?php
    class Order
    {
        public function Calculo_Items(){
            public function calculateTotalSum(){/*...*/}
            
        }

        public function Obtener_Items(){
            public function getItems(){/*...*/}
            public function getItemCount(){/*...*/}
        }
        
        public function Orden_Item(){
            public function addItem($item){/*...*/}
            public function deleteItem($item){/*...*/}
        }
        
        public function Mostrar_info(){
            public function printOrder(){/*...*/}
            public function showOrder(){/*...*/}
        }
        
        public function Carga_y_Actualizado(){
            public function load(){/*...*/}
            public function save(){/*...*/}
            public function update(){/*...*/}
        }
        
        public function delete(){/*...*/}
    }


<?php
    class Programmer
    {
        public function code()
        {
            return 'coding';
        }

        public function process(){
            code();
        }

    }
    class Tester
    {
        public function test()
        {
            return 'testing';
        }

        public function process(){
            test();
        }
    }

    class ProjectManagement {
        public function process(array $members) {
            foreach( $members as $member ) {
                $member->process();
            }
        }
    }