Partage
  • Partager sur Facebook
  • Partager sur Twitter

[code SOLID] Open/Close principle

Sujet résolu
    19 septembre 2019 à 16:40:01

    Bonjour, 

    Je cale sur un exercice depuis plusieurs jours... bref : j'ai besoin d'aide pour comprendre et exécuter le principe Open/Close d'un code SOLID.

    Je travaille sur ce code : https://github.com/OpenClassrooms-Student-Center/learn-solid-php-code

    Voici la classe Music :

    <?php
    
    namespace App\Models;
    
    use App\Models\Music\Mp3;
    
    class Music
    {
        private $id;
        private $title;
        private $file;
        private $albumId;
    
        public function __construct($map)
        {
            $this->id = $map['id'];
            $this->title = $map['title'];
            $this->albumId = $map['album_id'];
            $this->file = $map['file'];
        }
    
        public static function initialize($data = array())
        {
            if (isset($data['id'])) {
                $map['id'] = $data['id'];
            } else {
                $map['id'] = md5(microtime());
            }
            if (isset($data['title'])) {
                $map['title'] = $data['title'];
            } else {
                $map['title'] = '';
            }
            if (isset($data['file'])) {
                $map['file'] = $data['file'];
            } else {
                $map['file'] = '';
            }
            if (isset($data['album_id'])) {
                $map['album_id'] = $data['album_id'];
            } else {
                $map['album_id'] = 0; // this value is not possible
            }
    
            return self::factory($map);
        }
    
        public static function factory($map)
        {
            $extension = pathinfo($map['file'], PATHINFO_EXTENSION);
            switch ($extension) {
                case 'mp3':
                    return new Mp3($map);
                    break;
                case 'ogg':
                    break;
                default:
                    return new Music($map);
            }
        }
    
        public function update($updateData)
        {
            if (isset($updateData['title'])) {
                $this->title = $updateData['title'];
            }
        }
    
        public function getId()
        {
            return $this->id;
        }
    
        public function setId($id)
        {
            $this->id = $id;
        }
    
        public function getFile()
        {
            return $this->file;
        }
    
        public function getTitle()
        {
            return $this->title;
        }
    
        public function setTitle($title)
        {
            $this->title = $title;
        }
    
        public function getAlbumId()
        {
            return $this->albumId;
        }
    
        public function setAlbumId($albumId)
        {
            $this->albumId = $albumId;
        }
    }
    

    On voit bien que dans la méthode  factory(), il y a des if qui rendent la classe ouverte à des modifications lorsqu'on veut ajouter d'autres types de musique. Il faut alors agit pour fermer (Close) la classe aux modifications.

    Il y a déjà dans le code la classe Mp3 :

    <?php
    
    namespace App\Models\Music;
    
    use App\Models\Music;
    
    class Mp3 extends Music
    {
        public function __construct($map)
        {
            parent::__construct($map);
        }
    }

    L'idée, je pense, est alors de créer une interface MusicTypeInterface qui sera implémenté par les différents types de musique...

    <?php
    
    namespace App\Classes\Music;
    
    interface MusicTypeInterface
    {
        public static function factory($map);
    }



    Cette classe est alors implémentée par les différents types de musiques : Mp3, Ogg... Mais est-ce que Music est aussi un type de musique ?

    Par exemple, si j'ai bien compris, cela donne pour Mp3 :

    <?php
    
    namespace App\Models\Music;
    
    use App\Models\Music;
    use App\Classes\Music\MusicType
    
    class Mp3 extends Music implements MusicTypeInterface
    {
        public function __construct($map)
        {
            parent::__construct($map);
        }
    
        public static function factory($map)
        {
        	return new Mp3($map);
        }
    }


    C'est là que je bloque... ou plutôt que je tourne en rond car la classe Mp3 étend la classe Music...

    , le type de musique doit être appelé par injection de dépendance dans la classe Music. Du coup, ça modifie le constructeur et ajoute une propriété :
    <?php
    
    namespace App\Models;
    
    use App\Classes\Music\MusicTypeInterface;
    
    
    class Music implements MusicTypeInterface
    {
        private $id;
        private $title;
        private $file;
        private $albumId;
    
        private $musicType;
    
        public function __construct($map, MusicTypeInterface $musicType)
        {
            $this->id = $map['id'];
            $this->title = $map['title'];
            $this->albumId = $map['album_id'];
            $this->file = $map['file'];
    
            $this->musicType = $musicType;
        }
    
        public static function initialize($data = array())
        {
            //...
            return self::factory($map);
        }
    
        public static function factory($map)
        {
            return new Music($map);
        }
    
        //...
    }
    
    Du coup, est-ce que je dois aussi modifier le constructeur de Mp3 ? je ne comprends pas, je tourne en rond o_O 
    et puis quel est l'intérêt de faire des classes de types de musique différents alors qu'au final j'ai l'impression qu'on fait la même chose... Dans le reste du code de l'application, seule la fonction statique initialize() est appelée. La classe Music n'est jamais implémentée donc au final, on s'en fout du type de musique ? Vraiment je ne comprends rien à comment et pourquoi cet exercice !:(
    j'ai besoin de vos lumières s'il vous plaît !!!



    -
    Edité par Squirrel Jo 19 septembre 2019 à 17:34:33

    • Partager sur Facebook
    • Partager sur Twitter
      19 septembre 2019 à 16:45:41

      Salut,

      une relecture de la partie héritage serait bien ;)

      Music == classe mère

      Mp3 == classe Fille

      Lors d'un héritage, la classe fille peut accéder à TOUTES les méthodes protected | public de la classe mère

      Si le constructeur parent est modifié, il faut modifier son appel, tu peux très bien avoir un constructeur de Mp3 différent de Music MAIS l'appel de __parent() doit respecter les paramètres de Music::__construct()

      • Partager sur Facebook
      • Partager sur Twitter
        19 septembre 2019 à 16:57:42

        christouphe a écrit:

        Si le constructeur parent est modifié, il faut modifier son appel, tu peux très bien avoir un constructeur de Mp3 différent de Music MAIS l'appel de __parent() doit respecter les paramètres de Music::__construct()


        d'accord, c'est pour cela que je parle de tourner en rond, je me retrouve à mettre des $musicType partout partout... 

        apparemment j'ai pas su expliquer où était mon problème ...

        -
        Edité par Squirrel Jo 19 septembre 2019 à 17:19:32

        • Partager sur Facebook
        • Partager sur Twitter
          19 septembre 2019 à 19:18:22

          Pourquoi tu passe un objet de l'interface que Music doit implémenter ???

          implements <=> je prends les méthodes de l'interface, et je les code.

          Il est là ton problème

          -
          Edité par christouphe 19 septembre 2019 à 19:19:35

          • Partager sur Facebook
          • Partager sur Twitter
            20 septembre 2019 à 11:21:39

            christouphe a écrit:

            Pourquoi tu passe un objet de l'interface que Music doit implémenter ???

            implements <=> je prends les méthodes de l'interface, et je les code.

            Il est là ton problème

            -
            Edité par christouphe il y a environ 15 heures


            Mais ouais ! merci !!!! :honte:

            Pour ceux que cela intéresse, au final ça donne :

            MusicTypeInterface :

            <?php
            
            namespace App\Classes\Music;
            
            interface MusicTypeInterface
            {
                public static function factory($map);
            }

            Music :

            <?php
            
            namespace App\Models;
            
            use App\Classes\Music\MusicTypeInterface;
            
            
            class Music implements MusicTypeInterface
            {
                private $id;
                private $title;
                private $file;
                private $albumId;
            
                public function __construct($map)
                {
                    $this->id = $map['id'];
                    $this->title = $map['title'];
                    $this->albumId = $map['album_id'];
                    $this->file = $map['file'];
            
                }
            
                public static function initialize($data = array())
                {
                    if (isset($data['id'])) {
                        $map['id'] = $data['id'];
                    } else {
                        $map['id'] = md5(microtime());
                    }
                    if (isset($data['title'])) {
                        $map['title'] = $data['title'];
                    } else {
                        $map['title'] = '';
                    }
                    if (isset($data['file'])) {
                        $map['file'] = $data['file'];
                    } else {
                        $map['file'] = '';
                    }
                    if (isset($data['album_id'])) {
                        $map['album_id'] = $data['album_id'];
                    } else {
                        $map['album_id'] = 0; // this value is not possible
                    }
            
                    return self::factory($map);
                }
            
                public static function factory($map)
                {
                    return new Music($map);
                }
            
                public function getMusicType()
                {
                    return $this->musicType;
                }
            
                public function update($updateData)
                {
                    if (isset($updateData['title'])) {
                        $this->title = $updateData['title'];
                    }
                }
            
                public function getId()
                {
                    return $this->id;
                }
            
                public function setId($id)
                {
                    $this->id = $id;
                }
            
                public function getFile()
                {
                    return $this->file;
                }
            
                public function getTitle()
                {
                    return $this->title;
                }
            
                public function setTitle($title)
                {
                    $this->title = $title;
                }
            
                public function getAlbumId()
                {
                    return $this->albumId;
                }
            
                public function setAlbumId($albumId)
                {
                    $this->albumId = $albumId;
                }
            }
            

            et Mp3 :

            <?php
            
            namespace App\Models\Music;
            
            use App\Models\Music;
            use App\Classes\Music\MusicTypeInterface
            
            class Mp3 extends Music implements MusicTypeInterface
            {
            
                public function __construct($map)
                {
                    parent::__construct($map);
                }
            
                public static function factory($map)
                {
                	return new Mp3($map);
                }
            }
            




            • Partager sur Facebook
            • Partager sur Twitter
              20 septembre 2019 à 11:31:57

              Dans MP3, pas besoin de surcharger (re-écrire) la méthode puisqu'elle est héritée de Music
              • Partager sur Facebook
              • Partager sur Twitter
                20 septembre 2019 à 13:09:37

                christouphe a écrit:

                Dans MP3, pas besoin de surcharger (re-écrire) la méthode puisqu'elle est héritée de Music


                Ah mais voilà ! Je comprends mieux le pourquoi de l'exercice maintenant, merci beaucoup Christouphe pour tes lumières !!!!

                [et je renomme MusicTypeInterface en MusicInterface ;)]

                -
                Edité par Squirrel Jo 20 septembre 2019 à 13:19:22

                • Partager sur Facebook
                • Partager sur Twitter
                  20 septembre 2019 à 13:16:55

                  Oui, dans l'exercice à première vue, c'est la bonne utilisation de l'héritage et des systèmes autour:

                  Surcharge, polymorphisme (n'existant pas en PHP) ...

                  • Partager sur Facebook
                  • Partager sur Twitter

                  [code SOLID] Open/Close principle

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown