Partage
  • Partager sur Facebook
  • Partager sur Twitter

architecture d'heritage

Sujet résolu
    25 août 2023 à 15:42:54

    Bonjour , 

    je suis debutant et j'aimerais avoir votre avis, je me demandais comment faire un heritage de maniere "propre" j'ai l'habitude de suivre une architecture qui me parait très mauvaise car la class qui n'herite d'aucune autre est souvent enorme voila a quoi cela ressemble 

    ce qui est pratique avec cette architecture est que je peut faire des conteneur de class 1 puis utiliser le polymorphisme cependant il semble plus coherent d'avoir une architecture telle que :

    Mais ne me permet pas d'avoir un seul conteneur pour gerer mes class cependant cela respecte beaucoup plus les principes de la POO il y a t'il des "techenique" ou une achitecture qui permet de regler ces probleme ? merci d'avance pour vos reponces .

    -
    Edité par MathéoBrument 25 août 2023 à 15:46:13

    • Partager sur Facebook
    • Partager sur Twitter
      25 août 2023 à 23:45:15

      Il n'y a pas de bonnes ou de mauvaises architectures de classe dans l'absolu

      Elle doit simplifier la création et la maintenance du code par une équipe de développeurs, pour implémenter une solution efficace à un problème donné.

      Je ne vois pas pourquoi la première architecture serait "intrinsèquement" moins POO que la seconde.

      C'est fonction de ce qui est modéliser avec cette architecture.

      Donnez un exemple concret, SVP.

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        26 août 2023 à 1:01:10

        je vous donne un exemple je risque de le changer car il n'est pas tres pratique mais m'a permis d'aprendre . Cette exemple est 2 class une fenetre et une Button , la fenetre peut ajouter des button et peut etre redimensionner etc ... voicie le code de mes class :

        Fenetre.h 

        #pragma once
        
        #ifndef FENETRE_H_INCLUDED
        #define FENETRE_H_INCLUDED
        
        #include "Button.h"
        #include <vector>
        
        class Fenetre : public sf::Drawable, public sf::Transformable
        {
        public :
        	// Constructeur
        	Fenetre(sf::Vector2f& m_positionSouris);
        	Fenetre(sf::Vector2f& m_positionSouris, sf::Texture& texture);
        	Fenetre(sf::Vector2f& m_positionSouris, sf::Vector2f sizeView);
        	Fenetre(sf::Vector2f& m_positionSouris, sf::FloatRect sizeView, sf::FloatRect view);
        
        	/// FONCTIONS ///
        	int update();
        	void addImage(sf::Sprite image, sf::Vector2f position);
        	void addLigne(sf::Vector2f size, sf::Vector2f position, sf::Color color);
        	void addText(sf::Vector2f position, sf::Font& font, std::string mot, sf::Color color, int size);
        
        	//ADDBUTTON
        	void addButton(sf::Vector2f position, sf::Font& font, std::string mot);
        	void addButton(sf::Vector2f position, sf::Font& font, std::string mot, sf::SoundBuffer& buffer);
        	void addButton(sf::Vector2f position, sf::Texture& texture, bool show);
        	void addButton(sf::Vector2f position, sf::Texture& texture, bool show, sf::Vector2f size);
        	void addButton(sf::Vector2f position, sf::RectangleShape forme);
        	void addButton(sf::Vector2f position, sf::Font& font, std::string mot, sf::RectangleShape forme);
        
        	// REMOVE
        	void removeButton();
        	void removeRect();
        	void removeText();
        	void removeImage();
        
        	/// SETTEURS ///
        	void setBackground(sf::Texture& texture);
        	void setButtonColor(sf::Vector3f RGB, int indice);
        	void setButtonSize(sf::Vector2f size, int cible);
        	void setTextcharacter(int i, int size);
        
        	/// GETTEURS ///
        	Button getButton(int i);
        	sf::View getView();
        
        protected :
        	/// FONCTIONS ///
        	virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
        
        	bool m_backgroundset;
        	/// VARIABLES SFML ///
        	sf::Vector2f& m_positionSouris;
        	sf::View m_view;
        	sf::Sprite m_sprite;
        	sf::RectangleShape m_back;
        	/// VARIABLES VECTORS ///
        	std::vector<sf::RectangleShape> m_tabRect;
        	std::vector<std::unique_ptr<Button>> m_tabButton;
        	std::vector<sf::Text> m_tabText;
        	std::vector<sf::Sprite> m_tabImage;
        
        };
        #endif // !FENETRE_H_INCLUDED
        

        Fenetre.cpp

        #include "../headers/Fenetre.h"
        
        Fenetre::Fenetre(sf::Vector2f& m_positionSouris) : m_positionSouris(m_positionSouris), m_backgroundset(false)
        {
        
        }
        
        Fenetre::Fenetre(sf::Vector2f& m_positionSouris, sf::Texture& texture) : m_positionSouris(m_positionSouris), m_backgroundset(false)
        {
        	m_sprite.setTexture(texture);
        	m_view.reset(sf::FloatRect(0, 0, 50, 50));
        }
        
        Fenetre::Fenetre(sf::Vector2f& m_positionSouris, sf::Vector2f sizeView) : m_positionSouris(m_positionSouris), m_backgroundset(false)
        {
        	m_back.setSize(sizeView);
        	m_back.setFillColor(sf::Color(0, 0, 0, 0));
        	m_view.reset(sf::FloatRect(0, 0, sizeView.x, sizeView.y));
        }
        
        Fenetre::Fenetre(sf::Vector2f& m_positionSouris, sf::FloatRect sizeView, sf::FloatRect view) : m_positionSouris(m_positionSouris), m_backgroundset(false)
        {
        	m_back.setPosition(sizeView.left, sizeView.top);
        	m_back.setSize(sf::Vector2f(sizeView.width, sizeView.height));
        	m_back.setFillColor(sf::Color(0, 0, 0, 200));
        	m_view.reset(sf::FloatRect(sizeView));
        	m_view.setViewport(view);
        }
        
        void Fenetre::addImage(sf::Sprite image, sf::Vector2f position)
        {
        	image.setPosition(position);
        	m_tabImage.push_back(image);
        }
        
        void Fenetre::addLigne(sf::Vector2f size, sf::Vector2f position, sf::Color color)
        {
        	sf::RectangleShape rect(size);
        	rect.setPosition(position);
        	rect.setFillColor(color);
        	m_tabRect.push_back(rect);
        }
        
        void Fenetre::setTextcharacter(int i, int size)
        {
        	m_tabText[i].setCharacterSize(size);
        }
        
        void Fenetre::addText(sf::Vector2f position,sf::Font& font, std::string mot, sf::Color color, int size)
        {
        	sf::Text txt(mot, font);
        	txt.setCharacterSize(size);
        	txt.setPosition(position);
        	txt.setFillColor(color);
        	m_tabText.push_back(txt);
        }
        
        void Fenetre::addButton(sf::Vector2f position, sf::Font& font, std::string mot)
        {
        	m_tabButton.push_back(std::make_unique<TextButton>(position, font, mot));
        }
        
        void Fenetre::addButton(sf::Vector2f position, sf::Font& font, std::string mot, sf::SoundBuffer& buffer)
        {
        	m_tabButton.push_back(std::make_unique<SoundTextButton>(position, font, mot, buffer));
        }
        
        void Fenetre::addButton(sf::Vector2f position, sf::Texture& texture, bool show)
        {
        	m_tabButton.push_back(std::make_unique<ImageButton>(position, texture, show));
        }
        
        void Fenetre::addButton(sf::Vector2f position, sf::Texture& texture, bool show, sf::Vector2f size)
        {
        	m_tabButton.push_back(std::make_unique<AnimatedButton>(position, texture, show, size));
        }
        
        void Fenetre::addButton(sf::Vector2f position, sf::RectangleShape forme)
        {
        	m_tabButton.push_back(std::make_unique<ShapeButton>(position, forme));
        }
        
        void Fenetre::addButton(sf::Vector2f position, sf::Font& font, std::string mot, sf::RectangleShape forme)
        {
        	m_tabButton.push_back(std::make_unique<TextButtonShape>(position, font, mot, forme));
        }
        
        void Fenetre::removeButton()
        {
        	m_tabButton.pop_back();
        }
        
        void Fenetre::removeRect()
        {
        	m_tabRect.pop_back();
        }
        
        void Fenetre::removeText()
        {
        	m_tabText.pop_back();
        }
        
        void Fenetre::removeImage()
        {
        	m_tabImage.pop_back();
        }
        
        
        void Fenetre::setButtonSize(sf::Vector2f size, int cible)
        {
        	m_tabButton[cible]->setSize(size);
        }
        
        void Fenetre::setBackground(sf::Texture& texture)
        {
        	m_sprite.setTexture(texture);
        	m_backgroundset = true;
        }
        
        void Fenetre::setButtonColor(sf::Vector3f RGB, int indice)
        {
        	m_tabButton[indice]->setColor(RGB);
        }
        
        Button Fenetre::getButton(int i)
        {
        	if (i >= 0 && i < m_tabButton.size() && m_tabButton.empty() == false)
        		return *m_tabButton[i];
        }
        
        sf::View Fenetre::getView()
        {
        	return m_view;
        }
        
        int Fenetre::update()
        {
        	int indice = 0;
        	for (auto& object : m_tabButton)
        	{
        		if (object->getCollision(m_positionSouris))
        		{
        			if (object->getUdpt() == false)
        			{
        				object->update();
        				object->setUdpt(true);
        			}
        			if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
        				return indice;
        		}
        		else if (object->getCollision(m_positionSouris) == false && object->getUdpt())
        		{
        			object->update();
        			object->setUdpt(false);
        		}
        		indice++;
        	}
        	return -1;
        }
        
        void Fenetre::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
        	target.setView(m_view);
        	target.draw(m_back);
        	if (m_backgroundset)
        		target.draw(m_sprite);
        	if (m_tabRect.empty() == false)
        		for (auto& object : m_tabRect)
        			target.draw(object);
        	if (m_tabImage.empty() == false)
        		for (auto& object : m_tabImage)
        			target.draw(object);
        	if (m_tabText.empty() == false)
        		for (auto& object : m_tabText)
        			target.draw(object);
        	if (m_tabButton.empty() == false)
        		for (auto& button : m_tabButton)
        		{
        			button->setAnim();
        			target.draw(*button);
        		}
        }

        Button.h

        #pragma once
        
        
        
        #ifndef BUTTON_H_INCLUDED
        
        #define BUTTON_H_INCLUDED
        
        
        
        #include <SFML/Graphics.hpp>
        
        #include <SFML/Audio.hpp>
        
        #include <string>
        
        #include <iostream>
        
        
        
        // BUTTON
        
        class Button : public sf::Drawable, public sf::Transformable
        
        {
        
        public :
        
        // Constructeur
        
        Button();
        
        Button(const sf::Vector2f& position);
        
        
        
        // SETTEURS 
        
        void setPosition(sf::Vector2f position);
        
        virtual void setColor(sf::Vector3f RGB);
        
        virtual void setSize(sf::Vector2f size);
        
        virtual void setAnim();
        
        
        
        // GETTEURS 
        
        sf::Vector2f getPosition();
        
        virtual bool getCollision(sf::Vector2f& positionObject);
        
        bool getUdpt();
        
        
        
        /// FONCTIONS ///
        
        virtual void update();
        
        void setUdpt(bool etat);
        
        
        
        protected :
        
        /// FONCTIONS ///
        
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
        
        
        
        /// VARIABLES ///
        
        sf::Color m_updateColor;
        
        bool m_update = false;
        
        sf::Vector2f m_position;
        
        
        
        };
        
        
        
        // TEXTBUTTON
        
        class TextButton : public Button
        
        {
        
        public:
        
        // Constructeur
        
        TextButton();
        
        TextButton(const sf::Vector2f& position, sf::Font& font, const std::string& mot);
        
        
        
        // SETTEURS 
        
        void setText(std::string mot);
        
        virtual void setSize(sf::Vector2f size);
        
        virtual void setColor(sf::Vector3f RGB);
        
        
        
        // GETTEURS 
        
        sf::Text getText();
        
        int getSize();
        
        int getcharactereSize();
        
        virtual bool getCollision(sf::Vector2f& positionObject);
        
        
        
        /// FONCTIONS ///
        
        virtual void update();
        
        virtual void update(sf::Color& updateColor);
        
        
        
        protected:
        
        /// FONCTIONS ///
        
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
        
        
        
        /// VARIABLES ///
        
        int m_charactereSize;
        
        sf::Text m_text;
        
        };
        
        
        
        // IMAGEBUTTON
        
        class ImageButton : public Button
        
        {
        
        public:
        
        // Constructeur
        
        ImageButton();
        
        ImageButton(const sf::Vector2f& position, sf::Texture& texture, bool show);
        
        
        
        // SETTEURS 
        
        void setTexture(sf::Texture &texture);
        
        virtual void setSize(sf::Vector2f size);
        
        
        
        // GETTEURS 
        
        sf::Sprite getSpite();
        
        virtual bool getCollision(sf::Vector2f& positionObject);
        
        
        
        /// FONCTIONS ///
        
        virtual void update();
        
        
        
        protected:
        
        /// FONCTIONS ///
        
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
        
        
        
        /// VARIABLES ///
        
        bool m_showRect;
        
        sf::Color m_color;
        
        sf::RectangleShape m_rectLum;
        
        sf::Sprite m_sprite;
        
        };
        
        
        
        // SOUNDBUTTON
        
        class SoundButton : public Button
        
        {
        
        public:
        
        // Constructeur
        
        SoundButton();
        
        SoundButton(const sf::Vector2f& position, sf::SoundBuffer& buffer);
        
        
        
        // SETTEURS 
        
        void setSound(sf::SoundBuffer& buffer);
        
        
        
        // GETTEURS 
        
        sf::Sound getSound();
        
        
        
        /// FONCTIONS ///
        
        virtual void update();
        
        
        
        protected:
        
        /// FONCTIONS ///
        
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
        
        
        
        /// VARIABLES ///
        
        int m_tempo;
        
        sf::SoundBuffer m_soundBuffer;
        
        sf::Sound m_sound;
        
        };
        
        
        
        // SHAPEBUTTON
        
        class ShapeButton : public Button
        
        {
        
        public:
        
        // Constructeur
        
        ShapeButton();
        
        ShapeButton(const sf::Vector2f& position, sf::RectangleShape forme);
        
        
        
        // SETTEURS 
        
        void setForme(sf::RectangleShape forme);
        
        virtual void setSize(sf::Vector2f size);
        
        virtual void setColor(sf::Vector3f RGB);
        
        
        
        // GETTEURS 
        
        sf::RectangleShape getForme();
        
        virtual bool getCollision(sf::Vector2f& positionObject);
        
        
        
        /// FONCTIONS ///
        
        virtual void update();
        
        virtual void update(sf::Color& updateColor);
        
        
        
        protected:
        
        /// FONCTIONS ///
        
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
        
        
        
        /// VARIABLES ///
        
        float m_purcentColor = 0.80f;
        
        sf::Color m_updateColor;
        
        sf::RectangleShape m_forme;
        
        sf::RectangleShape m_forme2;
        
        };
        
        
        
        // TEXTLISTBUTTON
        
        class TextListButton : public Button, public TextButton
        
        {
        
        public :
        
        TextListButton();
        
        TextListButton(const sf::Vector2f& position, sf::Font& font,const std::string& mot,const std::vector<std::string>& buttons);
        
        
        
        protected :
        
        
        
        };
        
        
        
        // ANIMATEDBUTTON
        
        class AnimatedButton : public Button, public ImageButton
        
        {
        
        public:
        
        // Constructeur
        
        AnimatedButton();
        
        AnimatedButton(const sf::Vector2f& position, sf::Texture& texture, bool show,const sf::Vector2f& size);
        
        
        
        // SETTEURS 
        
        virtual void setAnim();
        
        virtual void setSize(sf::Vector2f size);
        
        
        
        // GETTEURS 
        
        sf::Vector2i getAnim();
        
        virtual bool getCollision(sf::Vector2f& positionObject);
        
        
        
        /// FONCTIONS ///
        
        virtual void update();
        
        
        
        protected:
        
        /// FONCTIONS ///
        
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
        
        
        
        /// VARIABLES ///
        
        sf::Clock m_timer;
        
        sf::Vector2f m_size;
        
        sf::Vector2i m_anim;
        
        };
        
        
        
        // TEXTBUTTONSHAPE
        
        class TextButtonShape : public Button, public TextButton, public ShapeButton
        
        {
        
        public:
        
        TextButtonShape();
        
        TextButtonShape(const sf::Vector2f& position, sf::Font& font, const std::string& mot, sf::RectangleShape forme);
        
        
        
        // SETTEURS
        
        virtual void setColor(sf::Vector3f RGB);
        
        virtual void setSize(sf::Vector2f size);
        
        
        
        // GETTEURS
        
        virtual bool getCollision(sf::Vector2f& positionObject);
        
        
        
        // FONCTIONS
        
        virtual void update();
        
        
        
        protected :
        
        // FONCTIONS
        
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
        
        
        
        /// VARIABLES ///
        
        sf::Color m_updateColor;
        
        };
        
        
        
        // SOUNDTEXTBUTTON
        
        class SoundTextButton : public Button, public TextButton, public SoundButton
        
        {
        
        public :
        
        SoundTextButton();
        
        SoundTextButton(const sf::Vector2f& position, sf::Font& font, const std::string& mot, sf::SoundBuffer& buffer);
        
        
        
        // SETTEURS
        
        virtual void setColor(sf::Vector3f RGB);
        
        virtual void setSize(sf::Vector2f size);
        
        
        
        // GETTEURS
        
        virtual bool getCollision(sf::Vector2f& positionObject);
        
        
        
        // FONCTIONS
        
        virtual void update();
        
        
        
        protected :
        
        // FONCTIONS
        
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
        
        };
        
        
        
        #endif // !BUTTON_H_INCLUDED



        et Button.cpp
        #include "../headers/Button.h"
        
        // BUTTON
        
        Button::Button()
        {
        	m_updateColor = sf::Color(0, 0, 0);
        }
        
        Button::Button(const sf::Vector2f& position)
        {
        	m_position = position;
        	m_updateColor = sf::Color(0, 0, 0);
        }
        
        void Button::setPosition(sf::Vector2f position)
        {
        	m_position = position;
        }
        
        void Button::setAnim()
        {
        	// fonction virtuel
        }
        
        sf::Vector2f Button::getPosition()
        {
        	return m_position;
        }
        
        void Button::update()
        {
        	// rien a update ! (fonction virtuel)
        }
        
        void Button::setColor(sf::Vector3f RGB)
        {
        	m_updateColor = sf::Color(225 - RGB.x, 225 - RGB.y, 225 - RGB.z) ;
        }
        
        void Button::setSize(sf::Vector2f size)
        {
        	// fonction virtuel
        }
        
        void Button::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
        	//rien a draw ! (fonction virtuel)
        }
        
        bool Button::getCollision(sf::Vector2f& positionObject)
        {
        	//aucune collision ! (fonction virtuel)
        	return false;
        }
        
        bool Button::getUdpt()
        {
        	return m_update;
        }
        
        void Button::setUdpt(bool etat)
        {
        	m_update = etat;
        }
        
        // TEXTBUTTON
        
        TextButton::TextButton() : Button(), m_charactereSize(30)
        {
        	m_text.setCharacterSize(m_charactereSize);
        }
        
        
        TextButton::TextButton(const sf::Vector2f& position, sf::Font& font, const std::string& mot) : Button(position), m_charactereSize(30)
        {
        	m_text.setFont(font);
        	m_text.setPosition(position);
        	m_text.setString(mot);
        	m_text.setCharacterSize(m_charactereSize);
        }
        
        void TextButton::setText(std::string mot)
        {
        	m_text.setString(mot);
        }
        
        void TextButton::setSize(sf::Vector2f size)
        {
        	m_charactereSize = size.y;
        	m_text.setCharacterSize(m_charactereSize);
        	m_text.setLetterSpacing(size.x / m_text.getGlobalBounds().width);
        }
        
        int TextButton::getSize()
        {
        	return m_text.getString().getSize();
        }
        
        int TextButton::getcharactereSize()
        {
        	return m_charactereSize ;
        }
        
        void TextButton::setColor(sf::Vector3f RGB)
        {
        	m_updateColor = sf::Color(225 - RGB.x, 225 - RGB.y, 225 - RGB.z);
        	m_text.setFillColor(sf::Color(RGB.x, RGB.y, RGB.z));
        }
        
        sf::Text TextButton::getText()
        {
        	return m_text;
        }
        
        bool TextButton::getCollision(sf::Vector2f& positionObject)
        {
        	sf::FloatRect hitbox = m_text.getGlobalBounds();
        	if (hitbox.contains(positionObject))
        		return true;
        	return false;
        }
        
        void TextButton::update()
        {
        	sf::Color color = m_text.getFillColor();
        	m_text.setFillColor(m_updateColor);
        	m_updateColor = color;
        }
        
        void TextButton::update(sf::Color& updateColor)
        {
        	m_text.setFillColor(updateColor);
        	updateColor = sf::Color(225 - updateColor.r, 225 - updateColor.g, 225 - updateColor.b);
        }
        
        void TextButton::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
        	target.draw(m_text);
        }
        
        // IMAGEBUTTON
        ImageButton::ImageButton() : Button(), m_showRect(false)
        {
        
        }
        
        ImageButton::ImageButton(const sf::Vector2f& position, sf::Texture& texture, bool show) : Button(position), m_showRect(show)
        {
        	m_sprite.setTexture(texture);
        	m_sprite.setPosition(position);
        	m_rectLum.setSize(sf::Vector2f(m_sprite.getGlobalBounds().width, m_sprite.getGlobalBounds().height));
        	m_rectLum.setPosition(position);
        	m_rectLum.setFillColor(sf::Color(225, 225, 225, 0));
        	m_color = sf::Color(225, 225, 225, 30);
        }
        
        void ImageButton::setTexture(sf::Texture& texture)
        {
        	m_sprite.setTexture(texture);
        }
        
        void ImageButton::setSize(sf::Vector2f size)
        {
        	m_sprite.setScale(size);
        	m_rectLum.setSize(sf::Vector2f(m_rectLum.getSize().x * size.x, m_rectLum.getSize().y * size.y));
        }
        
        sf::Sprite ImageButton::getSpite()
        {
        	return m_sprite;
        }
        
        bool ImageButton::getCollision(sf::Vector2f& positionObject)
        {
        	sf::FloatRect hitbox = m_sprite.getGlobalBounds();
        	if (hitbox.contains(positionObject))
        		return true;
        	return false;
        }
        
        void ImageButton::update()
        {
        	sf::Color color= m_rectLum.getFillColor();
        	m_rectLum.setFillColor(m_color);
        	m_color = color;
        }
        
        void ImageButton::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
        	if (m_showRect)
        		target.draw(m_rectLum);
        	target.draw(m_sprite);
        }
        
        // SOUNDBUTTON
        
        SoundButton::SoundButton() : Button(), m_tempo(0)
        {
        
        }
        
        SoundButton::SoundButton(const sf::Vector2f& position, sf::SoundBuffer& buffer) : Button(position), m_soundBuffer(buffer), m_tempo(0)
        {
        	m_sound.setBuffer(m_soundBuffer);
        }
        
        void SoundButton::setSound(sf::SoundBuffer& buffer)
        {
        	m_soundBuffer = buffer;
        	m_sound.setBuffer(m_soundBuffer);
        }
        
        sf::Sound SoundButton::getSound()
        {
        	return m_sound;
        }
        
        void SoundButton::update()
        {
        	if (m_tempo%2 == 0)
        		m_sound.play();
        	m_tempo++;
        }
        
        void SoundButton::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
        	//rien a draw ! (fonction virtuel)
        }
        
        // SHAPEBUTTON
        ShapeButton::ShapeButton() : Button()
        {
        	m_updateColor = sf::Color(0, 0, 0);
        }
        
        ShapeButton::ShapeButton(const sf::Vector2f& position, sf::RectangleShape forme) : Button(position), m_forme(forme)
        {
        	m_forme.setPosition(position);
        	m_updateColor = sf::Color(225 - m_forme.getFillColor().r, 225 - m_forme.getFillColor().g, 225 - m_forme.getFillColor().b);
        	m_forme2.setFillColor(sf::Color(m_forme.getFillColor().r * m_purcentColor, m_forme.getFillColor().g * m_purcentColor, m_forme.getFillColor().b * m_purcentColor));
        	m_forme2.setSize(sf::Vector2f(m_forme.getSize().x - 8, m_forme.getSize().y - 8));
        	m_forme2.setPosition(sf::Vector2f(m_forme.getPosition().x + 4, m_forme.getPosition().y + 4));
        }
        
        void ShapeButton::setForme(sf::RectangleShape forme)
        {
        	m_forme = forme;
        	m_updateColor = sf::Color(225 - m_forme.getFillColor().r, 225 - m_forme.getFillColor().g, 225 - m_forme.getFillColor().b);
        	m_forme2.setFillColor(sf::Color(m_forme.getFillColor().r * m_purcentColor, m_forme.getFillColor().g * m_purcentColor, m_forme.getFillColor().b * m_purcentColor));
        	m_forme2.setSize(sf::Vector2f(m_forme.getSize().x - 8, m_forme.getSize().y - 8));
        	m_forme2.setPosition(sf::Vector2f(m_forme.getPosition().x + 4, m_forme.getPosition().y + 4));
        }
        
        void ShapeButton::setColor(sf::Vector3f RGB)
        {
        	m_updateColor = sf::Color(225 - RGB.x, 225 - RGB.y, 225 - RGB.z);
        	m_forme.setFillColor(sf::Color(RGB.x, RGB.y, RGB.z));
        	m_forme2.setFillColor(sf::Color(RGB.x * m_purcentColor, RGB.y * m_purcentColor, RGB.z * m_purcentColor));
        }
        
        void ShapeButton::setSize(sf::Vector2f size)
        {
        	m_forme.setSize(size);
        	m_forme2.setSize(sf::Vector2f(m_forme.getSize().x - 8, m_forme.getSize().y - 8));
        	m_forme2.setPosition(sf::Vector2f(m_forme.getPosition().x + 4, m_forme.getPosition().y + 4));
        }
        
        sf::RectangleShape ShapeButton::getForme()
        {
        	return m_forme;
        }
        
        bool ShapeButton::getCollision(sf::Vector2f& positionObject)
        {
        	sf::FloatRect hitbox = m_forme.getGlobalBounds();
        	if (hitbox.contains(positionObject))
        		return true;
        	return false;
        }
        
        void ShapeButton::update()
        {
        	sf::Color color = m_forme.getFillColor();
        	m_forme.setFillColor(m_updateColor);
        	m_forme2.setFillColor(sf::Color(m_updateColor.r * m_purcentColor, m_updateColor.g * m_purcentColor, m_updateColor.b * m_purcentColor));
        	m_updateColor = color;
        }
        
        void ShapeButton::update(sf::Color& updateColor)
        {
        	m_forme.setFillColor(updateColor);
        	m_forme2.setFillColor(sf::Color(updateColor.r * m_purcentColor, updateColor.g * m_purcentColor, updateColor.b * m_purcentColor));
        }
        
        void ShapeButton::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
        	target.draw(m_forme);
        	target.draw(m_forme2);
        }
        
        // ANIMATEDBUTTON
        
        AnimatedButton::AnimatedButton() : Button(), ImageButton()
        {
        
        }
        
        AnimatedButton::AnimatedButton(const sf::Vector2f& position, sf::Texture& texture, bool show,const sf::Vector2f& size)
        	: Button(position), ImageButton(position, texture, show), m_size(size), m_anim(sf::Vector2i(0,0))
        {
        	m_sprite.setTextureRect(sf::IntRect(0, 0, size.x, size.y));
        }
        
        void AnimatedButton::setAnim()
        {
        	if (m_timer.getElapsedTime().asMilliseconds() > 50)
        	{
        		m_timer.restart();
        		m_anim.x++;
        		if (m_anim.x > m_sprite.getTexture()->getSize().x / m_size.x)
        		{
        			m_anim.x = 0;
        			m_anim.y++;
        			if (m_anim.y > m_sprite.getTexture()->getSize().y / m_size.y)
        				m_anim.y = 0;
        			m_sprite.setTextureRect(sf::IntRect(m_anim.x * m_size.x, m_anim.y * m_size.y, m_size.x, m_size.y));
        		}
        	}
        }
        
        void AnimatedButton::setSize(sf::Vector2f size)
        {
        	m_sprite.setScale(size);
        }
        
        sf::Vector2i AnimatedButton::getAnim()
        {
        	return m_anim ;
        }
        
        bool AnimatedButton::getCollision(sf::Vector2f& positionObject)
        {
        	return ImageButton::getCollision(positionObject);
        }
        
        void AnimatedButton::update()
        {
        	setAnim();
        	ImageButton::update();
        }
        
        void AnimatedButton::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
        	ImageButton::draw(target, states);
        }
        
        // TEXTBUTTONSHAPE
        
        TextButtonShape::TextButtonShape() : TextButton(), ShapeButton()
        {
        
        }
        
        TextButtonShape::TextButtonShape(const sf::Vector2f& position, sf::Font& font, const std::string& mot, sf::RectangleShape forme) : TextButton(position, font, mot), ShapeButton(sf::Vector2f(position.x-4, position.y+4), forme)
        {
        	ShapeButton::setSize(sf::Vector2f(TextButton::getText().getGlobalBounds().width + 8 + 8, TextButton::getcharactereSize()));
        }
        
        void TextButtonShape::setColor(sf::Vector3f RGB)
        {
        	m_updateColor = sf::Color(225 - RGB.x, 225 - RGB.y, 225 - RGB.z);
        	ShapeButton::setColor(sf::Vector3f(225-RGB.x, 225-RGB.y, 225-RGB.z));
        	TextButton::setColor(RGB);
        }
        
        bool TextButtonShape::getCollision(sf::Vector2f& positionObject)
        {
        	return ShapeButton::getCollision(positionObject);
        }
        
        void TextButtonShape::update()
        {
        	TextButton::update(m_updateColor);
        	ShapeButton::update(m_updateColor);
        }
        
        void TextButtonShape::setSize(sf::Vector2f size)
        {
        	TextButton::setSize(size);
        	ShapeButton::setSize(sf::Vector2f(TextButton::getText().getGlobalBounds().width +8, TextButton::getcharactereSize()  +8));
        }
        
        void TextButtonShape::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
        	ShapeButton::draw(target, states);
        	TextButton::draw(target, states);
        }
        
        // SOUNDTEXTBUTTON
        SoundTextButton::SoundTextButton() : TextButton()
        {
        
        }
        
        SoundTextButton::SoundTextButton(const sf::Vector2f& position, sf::Font& font,const std::string& mot, sf::SoundBuffer& buffer) : TextButton(position, font, mot), SoundButton(position, buffer)
        {
        
        }
        
        void SoundTextButton::setColor(sf::Vector3f RGB)
        {
        	TextButton::setColor(RGB);
        }
        
        void SoundTextButton::setSize(sf::Vector2f size)
        {
        	TextButton::setSize(size);
        }
        
        bool SoundTextButton::getCollision(sf::Vector2f& positionObject)
        {
        	return TextButton::getCollision(positionObject);
        }
        
        void SoundTextButton::update()
        {
        	SoundButton::update();
        	TextButton::update();
        }
        
        void SoundTextButton::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
        	TextButton::draw(target, states);
        }
        
        la class TextListButton n'est pas encore faite mais cela n'est pas grave dans ce post on peut voir que ma class Fenetre prend un vector<Button> 
        et poscède plusieurs fois la fonction addButton chaque addButton ajoute un type de "sousButton" different ce qui deja pose probleme on voie que si je veut faire plus de Button je dois ajouter plus de paramètres mais imaginons que 2 "sousButton" on besoins de meme paramètres alors cette "solution" n'est meme plus efficace de plus on peut voir que dans la class principale Button j'ai une methode draw et collision qui ne sont par exemple pas nessecaire pour SoundButton qui poscede tout de meme cette fonction par heritage, le setAnime dans le draw de Fenetre.cpp est aussi une solution que j'ai trouver mais qui en fait est utile pour 1 seul Button "AnimatedButton" je vois donc clairement que mon programe a de grosse lacunes mais je ne vois pas de facon de regler ce probleme tout en gardant les avantage de ce programe , j'ai explorer la solution de if (typeid(object)->name() == "nameVariable") mais j'ai très vite abandonner car dans ce cas il faut ajouter un test a chaque Button ce que j'espère ne pas avoir besoins de le faire, n'hesiter pas si vous avez besoins de plus d'info sur un point du programe , mercie pour votre aide :)

        -
        Edité par MathéoBrument 26 août 2023 à 1:08:24

        • Partager sur Facebook
        • Partager sur Twitter
          27 août 2023 à 15:21:33

          Salut,

          Le gros problème que je vois dans ton architecture de base (je n'ai pas regardé le code de ta dernière intervention), c'est que tu as énormément de situation d'héritage dit "en diamant", avec des classes qui héritent de deux (ou plus) autres classes, qui héritent chacune de la même classe de base.

          Ainsi, sur ton premier schéma, tu as -- au premier niveau, les classes Classe2, Classe3 et Classe4 qui héritent "de base" de Classe1.  Jusque là, pas de problème ;)

          Mais, au deuxième niveau, tu as Classe5 qui hérite de Classe2 (qui hérite elle-même de Classe1) et de Classe3 (qui hérite -- elle aussi -- de Classe1), Classe6 qui hérite de Classe2 et de Classe4 (qui héritent toutes les deux de Classe1) et Classe7, qui hérite cette fois de Classe3 et de Classe4, qui héritent elles aussi toutes les deux de ... Classe1.

          Et enfin, au dernier niveau, on a Classe8 qui hérite de Classe5 (qui hérite de Classe2 et de Classe3, qui héritent toutes les deux de Classe1), de Classe6 (qui hérite de Classe2 et de Classe4 , qui héritent toutes les deux de Classe1) et de classe7(qui hérite Classe3 et de Classe4, qui héritent elles aussi toutes les deux de ... Classe1).

          Le gros problème, c'est que l'héritage est la relation la plus forte qui puisse exister entre deux classes, car la classe "dérivée" (celle qui hérite de l'autre) obtiens systématiquement l'ensemble des éléments que l'on retrouve dans la classe "de base" (celle qui sert à l'héritage de la classe dérivée).

          Et quand je dis l'ensemble des éléments, je veux dire: les données, bien sur, mais aussi les fonctions ... je veux dire : ABSOLUMENT TOUT.

          Alors, pourquoi est-ce un problème?  Hé bien, parce que, quand une classe (mettons Classe5) hérite de deux classes (Classe2 et Classe3, dans ton schéma) qui héritent elles-même de Classe1, cela signifie que l'on se retrouve, au niveau de Classe5, avec:

          • les données de Classe1 qui viennent de Classe2
          • les données de Classe1 qui viennent de ... Classe3
          • les fonctions de Classe1 qui viennent de Classe2 et
          • les fonctions de Classe1 qui viennent de ... Classe3

          Commences tu "tout doucement" à voir où se trouve le problème?

          Allez, je te mets sur la voie ;)

          Mettons que tu Crées une instance de Classe5 que l'on appellera -- par commodité -- obj5, et mettons que tu veuilles appeler une méthode héritée (de manière indirecte) de Classe1, mettons Methode1.

          On va appeler quelle Methode1?  Celle qui a été héritée à travers Classe2 ? ou celle qui a été héritée à travers Classe3 ???

          Tu me diras que cela n'a pas vraiment d'importance, et tu te tromperais très lourdement à ce sujet.

          Car il faut te dire que Methode1 va -- sans doute -- manipuler des données connues de Classe1 (et que l'on ne voit  pas dans ton schéma) et donc que la Methode1 qui vient de Classe2 va travailler sur les données de Classe1 qui viennent de ... Classe2 alors que la Methode1 qui vient de Classe3 va travailler sur les données (de Classe1 toujours) qui viennent ... de Classe3.

          Et ca, disons que ... ca va foutre un joyeux bordel...  Enfin, pas si joyeux que cela, parce que, si ca arrive, tu risque de te retrouver plus souvent qu'à ton tour à te demander "mais pourquoi telle valeur n'a pas été modifiée, alors que j'ai appelé la méthode qui va bien", alors que tu regardera sans doute la donnée de Classe1 qui vient de classe2 après avoir appelé la Methode1 de Classe1 qui vient ... de Classe3 (ou inversement).

          De plus, il faut te dire que ton compilateur, il est "pas très fut fut"...

          Enfin, si... Mais bon, cela reste un outil! et, comme tous les outils, il n'a que l'intelligence que ses développeurs ont bien voulus (ou ont été en mesure de) lui donner.

          Or, l'intelligence qui lui permettrait de choisir entre l'appel à la Methode1 qui vient de Classe2 et l'appel de la Methode1 qui vient de Classe3, c'est quelque chose qu'il est impossible de lui donner.

          Pourquoi? Ben, tout simplement, parce qu'il suffirait qu'on décide de lui faire choisire la Methode1 venue de la Classe2 pour que "quelqu'un" vienne se plaindre parce qu'il aurait voulu que le compilateur utilise la Methode1 venue de la Classe3 (et inversement).

          On en arrive donc au point ou, si tu essaye d'appeler "simplement" Methode1 depuis obj5, le compilateur va se plaindre parce que "désolé, j'ai un conflit entre Classe2::Methode1 et Classe3::Methode1 ... Laquelle voulez vous que j'appelle dans le cas présent?"

          Ce phénomène est connu sous le nom de "diamand de la mort" ... C'est te dire à quel point il est dangereux ;)

          Alors, il y a une solution pour résoudre ce genre de conflit, en utilisant ce que l'on appelle un "héritage virtuel". 

          En gros, cela revient à dire que, quoi qu'il arrive, peut importe le nombre de classe héritant de la même classe de base, il n'y aura jamais qu'une seule instance de cette classe de base au niveau de la "classe finale" (de la classe qui hérite de toutes les autres, et qui ne sert pas de classe de base pour une autre).

          Mais bon, cette solution vient avec un certain nombre de contraintes et de difficultés qui lui sont propres, et donc, elle ne fait que remplacer un joyeux bordel par un autre :p

          Le deuxième schéma que tu propose est -- malheureusement -- dans la même veine.  Du moins, pour ce qui concerne la Classe7 parce que l'on va retrouver au niveau de cette classe, deux instance de la Classe1, deux instances de la Classe2 et deux instance de la Classe3. Ce qui sera sans doute encore plus compliqué à gérer :p

          Alors bon, tout n'est pas perdu, car il y a une solution à ton problème ;).  Elle est inspirée par le quatrième principle SOLID : le I mis pour Interface Segregation Principle ;)

          Et voilà, le terme est lancé : ce qu'il te faut, ce sont des interfaces.

          Pour la première solution que je vois, on peut, par facilité, se baser sur les règles imposées par java en ce qui concerne les interfaces (voilà la preuve que tout n'est pas à jeter dans java :D ).

          En effet, en java (du moins, dans ses anciennes versions, car je crois que cela a changé depuis), une interface ne peut contenir aucune donnée et, par conséquent, on ne peut pas définir le moindre comportement de la moindre fonction directement (vu qu'il n'y a aucune donnée sur laquelle baser ce comportement).

          Alors, là, on a deux solutions : soit on respecte les règles imposées par java, en créant -- par exemple -- des interfaces de type SoundPlayer sous une forme proche de

          class SoundPlayer{
          public:
             /* on peut exposer le constructeur, car la présence
              * des fonctions virtuelles pures empêche de créer
              * une instance de SoundPlayer si ce n'est pas au 
              * travers d'une classe dérivée
              */
             SoundPlayer();
             /* on expose également la capacité à jouer un son
              * comme il s'agit d'une fonction virtuelle pure,
              * le compilateur refusera que l'on instancie cette
              * classe tant que l'on n'aura pas défini correctement
              * le comportement associé (au travers d'une classe 
              * dérivée)
              */
             virtual void playSound() = 0;
             /* si tu vois d'autres capacités intéressante,
              * tu peux les rajouter, sous la forme de 
              * fonctions virtuelles pures
              */
          protected:
              /* Par contre, on ne veut pas risquer de détruire
               * un objet si on ne le connait que comme étant
               * un SoundPlayer.
               * La destruction doit passer par la classe dérivée,
               * et le destructeur doit donc être protégé (mais peut
               * ne pas être virtuel
               */        
               ~SoundPlayer();               
          };

          De cette manière, à chaque fois que tu voudra associer la capacité de jouer un son à "un élément graphique", tu pourras le faire hériter de "SoundPlayer" et ... définir le comportement des fonctions virtuelles qui sont exposées sous une forme proche de

          class SoundButton : public Button, // ben oui, c'est un 
                                             // bouton avant tout
                              public SoundPlayer{
          public:
             void playSound() override;
          };
          
          /* et "quelque part" dans un fichier d'implémentation */
          void SoundButton::playSound(){
               /* tout ce qu'il faut faire */
          }

          Si tu as également envie d'afficher une image, tu envisageras sans doute de créer une interface ImageShower sous une forme proche de

          /* tu remarqueras que c'est la même structure générale que 
           * SoundPlayer ...
           * il n'y a que les noms des différentes fonctions qui changent 
           */
          class ImageShower{
          public:
             ImageShower();
          
             virtual void drawImage() = 0;
             /* si tu vois d'autres capacités intéressante,
              * tu peux les rajouter, sous la forme de 
              * fonctions virtuelles pures
              */
          protected:
               ~ImageShower();               
          };

          Et tu pourras "gentillement" créer un bouton qui affiche une image de la même manière, sous la forme de

          class ImageButton : public Button, // ben oui, c'est un 
                                             // bouton avant tout
                              public ImageShower{
          public:
             void drawImage() override;
          };
          
          /* et "quelque part" dans un fichier d'implémentation */
          void ImageButton::drawImage(){
               /* tout ce qu'il faut faire */
          }

          Par contre, les choses deviendront un peu plus compliquées lorsque tu voudras créer un bouton qui soit à la fois capable de jouer des sons et d'afficher des images...

          Car tu ne peux pas faire hériter ce bouton (appelons le ImageAndSoundButton) à la fois de SoundButon et de ImageButton, vu qu'ils héritent tous les deux de ... Button.

          Alors, tu as en fait pas mal de possibilités:

          • Soit tu fait hériter ImageAndSounButton de SoundButton et tu lui fait implémeter (en plus) l'interface ImageShower,
          • Soit tu fait hériter ImageAndSoundButton de ImageButton et tu lui fait implémenter (en plus) l'interface SoundPlayer
          • Soit, enfin, tu fait hériter ImageAndSoundButton de ... Button, et tu lui fait implémenter les interface SoundPlayer ET ImageShower.

          De manière générale, il est bien souvent préférable d'avoir une hiérarchie de classe "horzontale" que "verticale".

          Ce que je veux dire, c'est qu'il est souvent préférable d'avoir cinq classes qui dérivent toute d'une seule classe de base que d'avoir la classe2 qui hérite de la classe1, puis, au niveau inférieur, la classe3 qui dérive de la classe2, puis d'avoir, encore au niveau inférieur la classe4 qui dérive de la classe2 ...

          Disons que cela facilite les choses, surtout si certains comportements doivent systématiquement être redéfinis pour chacune des classes dérivées ;)

          Je te conseillerais donc d'adopter la troisième solution dans le cas présent ;).

          Le truc, en ayant respecté les règles imposées par (les anciennes versions de) java (car je crois que cela a changé depuis), c'est que, du coup, tu vas te retrouver à devoir ... implémenter plusieurs fois les comportements de tes interface.

          Et ce serait un peu idiot, car, les comportements d'une interface donnée seront -- sensiblement -- toujours les mêmes, quelque soit la classe qui les implémente.

          Si donc, nous pouvions implémenter ces comportements "une bonne fois pour toute", sans avoir besoin de "revenir dessus" à chaque fois qu'une autre classe doit implémenter l'interface en question, hé bien, cela nous simplifierait énormément la vie et nous éviterait sans doute énormément de problèmes, tu ne crois pas?

          Je te propose donc d'aller "un peu plus loin" dans la réflexion.

          Nous partons donc d'une situation dans laquelle une interface (selon java) ne peut avoir aucune donnée qui lui est propre et, pour laquelle nous ne pouvons fournir aucune implémentation pour les fonctions qu'elle expose.

          Nous avons donc des fonctions virtuelles pures, ce qui transforme "de facto" notre interface en ... classe abstraite; en classe qui ne peut en aucun cas être instanciée par elle-même; en classe qui ne peut être instanciée qu'au travers d'une classe qui hérite de cette classe et qui défini les comportements adéquats.

          Mais en fait ... Qu'est ce qui pourrait nous empêcher de faire en sorte que cette interface dispose effectivement "de toutes les données" lui permettant de fournir un comportement cohérent à toutes ses fonctions, pour autant que l'on s'arrange pour que cette interface ne puisse être instanciée ... qu'au travers de la classe qui en hérite?

          Car, il est très facile de forcer une classe à n'être instanciée qu'au travers de la classe qui en hérite: tu places son (ou ses) constructeur(s) dans l'accessibilité protégée, et seule les classes dérivées pourront y faire appel ;)

          Ainsi, on pourrait très bien créer une interface sous une forme qui risque d'en faire bondir plus d'un car les comportements des fonctions exposées sont directement clairement définis.  Cela pourrait prendre (pour SoundPlayer) une forme proche de

          class SoundPlayer{
          public:
             /* il n'y a que la capacité de jouer des sons qui 
              * soit expopsée "au tout public"
              */
            void playSound();
          protected:
             /* L'instantiation est réservée au classes dérivées */
             SoundPlayer(/* ... */);
             /* De même que la destruction */
             ~SoundPlayer();
          private : 
             /* Et les données utilisées pour jouer le son sont
              * strictement privée
              */
             /* je n'ai aucune idée de ce que sont ces données ... */
          }

          Et l'on pourrait -- bien sur, suivre exactement le même raisonnement avec l'interface ImageShower ;)

           Pour le reste, l'utilisation de ces interfaces resterait exactement la même que celle que j'ai expliquée plus haut, à ceci près qu'il ne sera même plus nécessaire (ni même conseillé) de redéfinir les comportement des fonctions exposées, dont tu auras remarqué qu'elle ne sont même plus virtuelles ;)

          • Partager sur Facebook
          • Partager sur Twitter
          Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
            27 août 2023 à 22:05:19

            Les interfaces java peuvent maintenant contenir des méthodes avec une definition d'implementation par défaut (qui peut appeler d'autres méthodes), des constantes (de classe) mais pas d'attributs. Sinon ca serait des classes abstraites, qui existent déjà.

            Çà ce que j'en sais, ca a été rajouté pour pouvoir faire évoluer les bibliothèques standard (dont certaines ne sont pas jeunes, et pas bien fichues) en ajoutant des fonctionnalités dans les interfaces existantes sans péter les codes qui implémentent ces interfaces

            -
            Edité par michelbillaud 27 août 2023 à 22:06:21

            • Partager sur Facebook
            • Partager sur Twitter
              27 août 2023 à 22:16:03

              Juste une remarque à 2 balles.

              La réponse de@koala01 n'est qu'une des manières de faire (l'une qui utilise le moins de concepts avancées comme des Design Pattern, etc...).

              Le cas de l'implémentation d'une architecture de classe pour la modélisation d'IHM est pathologique, il sert très régulièrement de cas d'illustration d'utilisation de modélisation "avancée".

              Donc si ce cas est juste pour vous faire apprendre les concepts d'héritage d'implémentation, c'est un très très mauvais cas d’illustration du concept.

              Votre code est truffé d’idiosyncrasie JAVA. Si cela vient de vous, c'est OK, si cela vient de votre source d'apprentissage du C++, je serais assez suspicieux sur la qualité de cette source (et encore plus si votre cas d'usage vient de ce cours).

              Mais vous vous posez de très bonnes questions, ce qui est loin d'être évident.

              Et on ne peut pas simplement y répondre par "faire ci ou ça", car une conception doit prendre en compte au maximum les fonctionnalités demandées en amont. Par exemple, le fait de vouloir faire des boutons "complexes" (je parlerais plutôt de contrôle customisable) devrait faire en sorte qu'un bouton puisse contenir une ou plusieurs fenêtres. Vous faites comment avec votre architecture ?

              Donc si on vous donne une solution à un problème donné, il y a de grosses chances qu'elle pose problème plus loin dans le projet. Ne pas négliger l'étape d'analyse dans un projet informatique.

              Donc les solutions ici proposées sont délibérément candide et à courte vue.

              >poscède plusieurs fois la fonction addButton chaque addButton ajoute un type de "sousButton" different ce qui deja pose problem ..

              Pourquoi ne pas avoir qu'une fonction "addButton" qui prend directement le bouton à ajouter ?

              >dans la class principale Button j'ai une methode draw et collision qui ne sont par exemple pas nessecaire pour SoundButton

              Est-ce que la classe "SoundButton" a un sens ? Ci ce n'est pas un bouton, n'en dérivez pas.

              => Si vous voulez que les informations de son soit associées à une fenêtre (ce en quoi je doute de la pertinence), elle n'a qu'à contenir des "controles", les boutons n'en n'étant qu'un sous-type et faire de la classe représentant un son une classe "contrôle" et non une classe bouton.

              => Ne pas appeler "draw" sur tous les contrôles/button mais une fonction plus polysémique comme "pump" ou "update" depuis le code de la classe fenêtre.

              >le setAnime dans le draw de Fenetre.cpp est aussi une solution que j'ai trouver mais ...

              Pourquoi mettre son appel dans "AnimatedButton::update" ne suffirit-il pas ???

              >j'ai explorer la solution de if (typeid(object)->name() == "nameVariable")

              Dans l'absolu, très très mauvaise approche, très très peu maintenable.

              Donc, il fait lâcher le clavier, papier-crayon pour lister toutes les fonctionnalités attendues et faire une ébauche de solution de la "big picture"(vue d'ensemble), ne pas être un rat dans un couloir d'un labyrinthe.

              • Partager sur Facebook
              • Partager sur Twitter
              Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                27 août 2023 à 23:31:50

                michelbillaud a écrit:

                Les interfaces java peuvent maintenant contenir des méthodes avec une definition d'implementation par défaut (qui peut appeler d'autres méthodes), des constantes (de classe) mais pas d'attributs. Sinon ca serait des classes abstraites, qui existent déjà.

                Çà ce que j'en sais, ca a été rajouté pour pouvoir faire évoluer les bibliothèques standard (dont certaines ne sont pas jeunes, et pas bien fichues) en ajoutant des fonctionnalités dans les interfaces existantes sans péter les codes qui implémentent ces interfaces

                -
                Edité par michelbillaud il y a environ 1 heure


                Oui, je sais, c'est bien pour cela que j'ai pris la peine de préciser "du moins, dans ses anciennes versions".

                Car ce changement est sommes toutes "assez récent", il me semble ;)

                • Partager sur Facebook
                • Partager sur Twitter
                Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                  28 août 2023 à 10:03:34

                  Bonjour bacelar,

                  pour la fonction addButton j'ai du mal a trouver une solution le fait de prendre un button a ajouter fait que le button n'est pas definie dans la meme zone que la fenetre j'ai penser a une solution du type

                  template<class T> void addButton(parametre1,..., parametreN) // on recupere un nombre de parametres variables
                  {
                  m_tabButton.push_back(std::make_unique<T>(parametre1,..., parametreN)); // le Button est cree dans la meme zone que la fenetre
                  }

                  cependant je ne sait pas si il est possible de faire addButton(parametre1,..., parametreN)

                  et recuperer(parametre1,..., parametreN) il y aurrait aussi une condition pour verifier que T herite de Button mais la ce n'est plus un probleme d'architecture :)



                  -
                  Edité par MathéoBrument 28 août 2023 à 10:09:09

                  • Partager sur Facebook
                  • Partager sur Twitter
                    28 août 2023 à 10:50:13

                    Et pourquoi pas dans le genre

                    class Fenetre 
                    {
                       ....
                       public:
                           void addButton(Button &button);
                    };
                    


                    le job de la fenêtre n'étant pas de fabriquer les boutons, mais de les regrouper.  Et de façon polymorphe, en autorisant à ajouter des trucs de n'importe quel type qui étend/implémente Bouton.

                    En pratique, probablement avec des pointeurs (intelligents) plutôt qu'une référence.

                    -
                    Edité par michelbillaud 28 août 2023 à 10:51:50

                    • Partager sur Facebook
                    • Partager sur Twitter
                      28 août 2023 à 17:13:32

                      voicie ma nouvelle fonction de addButton

                      void Fenetre::addButton(Button& button)
                      {
                      	m_tabButton.push_back(new &button);
                      }

                      j'ai donc changer m_tabButton

                      std::vector<Button*> m_tabButton;

                      et cree une destructeur 

                      Fenetre::~Fenetre()
                      {
                      	for (int i = 0; i < m_tabButton.size(); i++)
                      	{
                      		delete m_tabButton[i];
                      		m_tabButton[i] = 0;
                      	}
                      }

                      michelbillaud j'ai essayer les pointeur intelligent malheureusement je passe par des pointeur normal car les unique_ptr ne peuvent pas prendre un Button deja cree il doit en cree un nouveau or il faut passer tout les arguments il y a une facon d'y parvenir mais par soucie de simpliciter j'ai choisie cette methode n'hesitez pas s'il y a un probleme majeur a me prevenir

                      -
                      Edité par MathéoBrument 28 août 2023 à 21:06:32

                      • Partager sur Facebook
                      • Partager sur Twitter
                        28 août 2023 à 22:56:22

                        MathéoBrument a écrit:

                        voicie ma nouvelle fonction de addButton

                        void Fenetre::addButton(Button& button)
                        {
                        	m_tabButton.push_back(new &button);
                        }


                        new, vraiment ?

                        > j'ai choisie cette methode n'hesitez pas s'il y a un probleme majeur a me prevenir

                        Je crois qu'il faut te laisser jouer avec pour que tu voies par toi-même les conséquences. Un problème majeur, ça se voit rapidement.  Si tu attends à ce que qu'on valide ce que tu fais chaque fois que tu écris une ligne, ça ne t'incite pas à réfléchir aux conséquences de tes choix.

                        -
                        Edité par michelbillaud 28 août 2023 à 22:59:14

                        • Partager sur Facebook
                        • Partager sur Twitter
                          28 août 2023 à 23:21:06

                          michelbillaud a écrit:

                          MathéoBrument a écrit:

                          voicie ma nouvelle fonction de addButton

                          void Fenetre::addButton(Button& button)
                          {
                          	m_tabButton.push_back(new &button);
                          }



                          new, vraiment ?

                          > j'ai choisie cette methode n'hesitez pas s'il y a un probleme majeur a me prevenir

                          Je crois qu'il faut te laisser jouer avec pour que tu voies par toi-même les conséquences. Un problème majeur, ça se voit rapidement.  Si tu attends à ce que qu'on valide ce que tu fais chaque fois que tu écris une ligne, ça ne t'incite pas à réfléchir aux conséquences de tes choix.

                          -
                          Edité par michelbillaud il y a 17 minutes

                          en effect j'ai rapidement vue le probleme ma solution est donc beaucoup plus simple je renvois le tableau en reference et le modifie dans le code 

                          std::vector<std::unique_ptr<Button>>& Fenetre::getTabButton()
                          {
                          	return m_tabButton;
                          }

                          dans le fichier qui ajoute des button (exemple d'un imageButton)

                          Lobby.getTabButton().push_back(std::make_unique<ImageButton>(sf::Vector2f(1268, 0), exitTexture));

                          voila cette solution est tres simple a comprendre je n'ai manifestement pas encore le niveau pour faire ce que je souhaite cet a dire faire ce qui est dans l'exemple mais dans une methode de Fenetre je retournerais peut etre le modifier plus tard :)




                          -
                          Edité par MathéoBrument 28 août 2023 à 23:21:32

                          • Partager sur Facebook
                          • Partager sur Twitter
                            29 août 2023 à 0:05:12

                            Salut,

                            Dans toute l'explication que j'ai pu donner, il y a énormément de choses que j'ai quand même passée sous silence...

                            La première est que, si tu veux avoir un code "facile à lire, facile à comprendre, facile à maintenir et à faire évoluer", il y a cinq principes "de base" et une loi à respecter.

                            Les cinq principe sont connus sous le terme SOLID :

                            • S pour SRP (Single Responsibility Principle / princie de la responsabilité unique ) : Chaque chose (chaque type de donnée, chaque donnée, chaque fonction) ne doit servir qu'à une et une seule chose
                            • O our OCP (Open Close Principle / principe "Ouvert / Fermé" ) : ton code doit être "ouvert aux évolutions" et "fermé aux modification.  Autrement dit, tu ne devrais pas avoir à modifier un code existant (et testé) pour pouvoir ajouter une nouvelle foncitonnalité
                            • LSP (Liskov Substitution Principle / principe de substitution de Liskov) : Dans une relation d'héritage, toute propriété valide de la classe mère doit également être valide pour la classe dérivée
                            • I (Interface Segregation Principle / principe de ségrégation des interfaces) : Il faut garder les interfaces les plus simples et séparées possibles, en faisant en sorte qu'elles n'exposent que les services absolument nécessaires, sans en rajouter qui ne le soient pas (nécessaires)
                            • D (Dependencies Inversion Principles / principe d'inversion des dépendances) :
                              • Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau, les deux doivent dépendre d'abstraction
                              • Les abstractions ne doivent pas dépendre de détails d'implémentation, ce sont les détails qui dépendent des abstractions

                            Et la loi dont je parle est connue sous le nom de "loi de Déméter": Si une donnée a de type A utilise en interne une donnée b de type B , l'utilisateur de l'objet a ne devrait pas avoir besoin de connaitre le type B pour pouvoir utiliser le A .

                            Je ne vais pas m'étendre sur ces principes ici (mon livre les couvre en long en large et en travers :D), mais, en cas de besoin, j'apporterai volontiers des précisions sur l'un ou l'autre ;)

                            Par contre, ce qu'il est important de retenir, c'est qu'il s'agit de principe de conception, c'est à dire qui doivent entrer en jeu AVANT que l'on ne commence à écrire la moindre ligne de code et donc, QU'ILS SE FOUTENT PAS MAL DE CE QUE LE LANGAGE (ou le compilateur) ACCEPTE OU NON : si le principe est respecté, alors, cela vaut la peine de s'intéresser au langage (et au compilateur) pour savoir si la soluton envisagée est "admise".  Par contre, si le principe n'est pas respecté à la base, alors, la solution doit être abandonnée, MEME SI LE LANGAGE (ou le compilateur) SEMBLE L'ACCEPTER.

                            La deuxième chose que j'ai totalement passée sous silence (et que bacelar a cité), c'est le fait qu'il existe des "constructions classiques", que l'on régulièrement dans les différents projets (y compris dans d'autres langages ) et qui sont appelés "patrons de conception" en francais (Desing Patterns, en anglais).

                            Ainsi, lorsque MichelBillaud te dit que "ta fenêtre ne doit pas construire les boutons mais les regrouper", hé bien, on se rend compte que cela se rattache au SRP car ... construire et regrouper sont effectivement deux choses tout à fait différentes ;)

                            Ainsi, si tu t'intéresse un tout petit peu au patrons de conceptions, tu trouveras très vite un patron nommé "fabrique" en francais (factory en anglais) dont le rôle est -- justement -- de prendre la responsabilité de ... fabriquer des éléments polymorphes.

                            De même, si saupoudre un peu de DIP la "grande image" que tu commence tout doucement à te faire de ton projet, tu te rendras compte, en continuant ton "étude" des patrons de conceptions les plus communs, que la capacité de jouer des sons et / ou d'afficher des images pourrait parfaitement être pris en carge par le patron ... décorateur (décorator en anglais).

                            Et ainsi de suite : plus tu respecteras l'ensemble des principes, plus tu te rendras compte qu'il devient "facile" de les respecter, et plus tu parviendra à trouver des solutions "plus faciles" que le fait d'utiliser l'héritage.

                            Bien sur, il faut, comme disait Einstein, rendre les choses "Aussi complexes que nécessaires, mais guère plus", dans le sens où, tes besoins étant complexes, tu ne pourras clairement pas éviter d'avoir "un certain niveau de complexité" dans ton code.  Il faut juste veiller à ne pas rendre les choses "plus complexes que nécessaire" ;).

                            Au final, il faut te dire qu'il y a  ... des tonnes de solutions pour arriver à ce que tu veux faire.  Et aucune ne peut être mauvaise à partir du moment où elle respecte les principes de conception. Sur ce point, ton imagination est la seule limite ;)

                            Par contre, il semble également que certaines solutions seront sans doute "meilleures" ou, à tout le moins "mieux adpatées" à ce que tu veux (ou envisage de) faire. Et, malheureusement, à ce niveau là, seule l'expérience te permettra de savoir "ce qui marche bien" et ce qui "marche, mais pas trop" :p

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                              29 août 2023 à 17:52:58

                              MathéoBrument a écrit:

                              michelbillaud a écrit:

                              Je crois qu'il faut te laisser jouer avec pour que tu voies par toi-même les conséquences. Un problème majeur, ça se voit rapidement.  Si tu attends à ce que qu'on valide ce que tu fais chaque fois que tu écris une ligne, ça ne t'incite pas à réfléchir aux conséquences de tes choix.

                              -
                              Edité par michelbillaud il y a 17 minutes

                              en effect j'ai rapidement vue le probleme ma solution est donc beaucoup plus simple je renvois le tableau en reference et le modifie dans le code 

                              std::vector<std::unique_ptr<Button>>& Fenetre::getTabButton()
                              {
                              	return m_tabButton;
                              }

                              dans le fichier qui ajoute des button (exemple d'un imageButton)

                              Lobby.getTabButton().push_back(std::make_unique<ImageButton>(sf::Vector2f(1268, 0), exitTexture));

                              voila cette solution est tres simple a comprendre

                              -
                              Edité par MathéoBrument il y a environ 13 heures

                              Pour en revenir à de bons principes

                              • la Fenetre rassemble des Boutons
                              • La façon technique de réaliser ce rassemblement de Boutons (par un vecteur), c'est un détail technique interne de la Fenetre
                              • les détails techniques, c'est ses oignons, pas celle du code qui va utiliser une Fenetre
                              • donc à priori il n'y a aucune raison d'avoir un "accesseur" qui rend public les "parties intimes" de la fenêtre et permet à n'importe qui de les tripoter.
                              Bref, tu trouves peut être ta solution très simple, mais elle ne respecte pas un principe de base : ne pas donner accès aux détails de réalisation.
                              -
                              Bon, pour dérouiller mon C++, voila un exemple de code, avec une fenêtre qui contient un vecteur de pointeurs (uniques) vers des éléments


                              La fonction main, qui construit une fenêtre avec deux éléments (de types différents, pour tester le polymorphisme)
                              int main()
                              {
                                  Window w;
                                  
                                  std::unique_ptr<Element> button(new Button("hello"));
                                  std::unique_ptr<Element> image (new Image("selfie"));
                              
                                  w.add_element(button);
                                  w.add_element(image);
                              
                                  w.process_elements();
                              
                                  return EXIT_SUCCESS;
                              }
                              Quand ça s'exécute, ça produit ça
                              In the window:
                              - A button named hello
                              - Image selfie
                              
                              La fenêtre est un regroupement d'éléments, avec une fonction pour les traiter tous
                              // Regroupement d'élements
                              
                              class Window
                              {
                                  std::vector<std::unique_ptr<Element>> m_elements;
                              public:
                                  void add_element(std::unique_ptr<Element> &e)
                                  {
                                      m_elements.push_back(std::move(e));
                                  }
                              
                                  void process_elements()
                                  {
                                      std::cout << "In the window:" << std::endl;
                                      for (auto & e : m_elements) {
                                          e->process();
                                      }
                                  }
                              };

                              Rq: Dans add_element, l'élément devient la propriété d'un pointeur contenu dans le vecteur,  d'où l'appel à std::move

                              La class Element est la classe (abstraite) de base
                              // Classe de Base (abstraite)
                              
                              class Element
                              {
                              public:
                                  virtual void process() = 0;
                                  virtual ~Element() {}
                              };
                              

                              Avec deux classes dérivées sans grande imagination
                              // Un bouton est un élément
                              
                              class Button : public Element
                              {
                                  std::string m_label;
                              public:
                                  Button (const std::string &label)
                                      : m_label{label}
                                  {}
                              
                                  virtual void process()
                                  {
                                      std::cout << "- A button named "
                                                << m_label << std::endl;
                                  };
                              };
                              
                              // une image est un Element
                              
                              class Image : public Element
                              {
                                  std::string m_description;
                              public:
                                  Image (const std::string &description)
                                      : m_description{description}
                                  {}
                              
                                  virtual void process()
                                  {
                                      std::cout << "- Image "
                                                << m_description << std::endl;
                                  };
                              };
                              




                              -
                              Edité par michelbillaud 29 août 2023 à 18:20:23

                              • Partager sur Facebook
                              • Partager sur Twitter

                              architecture d'heritage

                              × 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