POURQUOI CE BLOG, POUR QUI ?


POURQUOI CE BLOG, POUR QUI ?
Ce Blog s'adresse à tous ceux qui sont passionnés par les sciences informatiques , Professionnels,Etudiants,Amateurs ...
Les sujets exposés dans la suite se rapporteront essentiellement sur l'analyse informatique,la programmation,le développement ainsi que à l'architecture IT.
QUI SUIS JE ?
Je suis Kangulungu Lubilanji, Consultant-Freelance sur les technologies .NET,C#,ASP.NET ... Contactez moi pour plus d'informations.

La Programmation OO: Chapitre 13. Abstraite, cette classe est sans objet

Chapitre 13.  Abstraite, cette classe est sans objet
Ce chapitre introduit la notion de classe abstraite et son exploitation lors du polymorphisme.

Disons d'abord que une méthode abstraite est une méthode qui se limite à sa seule signature, une méthode qui ne fait rien, à part se présenter.
En C# nous la déclarons de la manière suivante :
abstract public void evolue()

Classe abstraite, toute classe contenant au moins une méthode abstraite devient d'office abstraite. D'ailleurs C# force le trait, en vous obligeant à rajouter le mot-clé abstract dans la déclaration de la classe, comme suit :
public abstract class Ressource : ObjetSuperClasse { ... }
C# n'accepterait pas qu'une méthode abstraite ne fût définie dans une classe, elle-même déclarée comme abstraite (l'omission de la déclaration de la classe comme abstraite donnerait une erreur de compilation), mais le contraire ne s'applique pas. Ce langage accepte d'une classe qu'elle soit abstraite, alors qu'aucune méthode abstraite ne s'y trouve. Cela bloque ainsi la possibilité pour certaines classes de donner naissance à des objets, indifféremment du fait qu'elles intègrent ou non une méthode abstraite. Dans la pratique, très logiquement, une classe ne sera généralement abstraite que si une méthode abstraite s'y trouve.

« new » et  « abstract » incompatibles, new et abstract sont deux-mots-clés totalement incompatibles, en ce qu'aucune allocation de mémoire ne peut être effectuée pour des instances de classe abstraite. Si nous revenons à la définition première des classes abstraite, c'est-à-dire qu'elles contiennent au moins une méthode abstraite,cette interdiction doit vous paraître logique.

Supposons une classe contenant une méthode abstraite et pouvant donner naissance à des objets. Tout objet  se doit d'être capable d'exécuter tous les messages reçus. Qu'en serait-il du message issu de la méthode abstraite ? Le compilateur ne tiquerait pas, car la syntaxe du message est parfaitement correcte. Mais que faire à l'exécution, face à un corps d'instruction absent ? On enverrait un message qui dit de ne rien faire ? Cette possibilité a d'office été bannie par les langages OO, car un message se doit de faire quelque chose.
Notez pour l'anecdote qu'un corps d'instruction vide est considéré comme distinct de pas de corps d'instruction du tout : public void evolue() { } est différent de abstract public void evolue()
Tous les langages OO interdisent l'envoi de messages à partir de méthodes sans corps d'instruction, mais cette interdiction est levée pour des méthodes dont le corps d'instruction, bien qu'existant, est vide. Seules les premières méthodes sont abstraites, les autres sont stupides mais concrètes !

Abstraite de père en fils, au contraire des superclasses concrètes, les superclasses abstraites obligent à redéfinir les méthodes abstraites dans leurs sous-classes. Tant que la méthode abstraite n'est pas redéfinie dans les sous-classes, chacune de ces sous-classes se doit de rester abstraite, et aucune ne donnera naissance au moindre objet. Le compilateur se chargera de vérifier que vous maintenez l'abstraction, des sous-classes en sous-classes, jusqu'à ce que toutes les méthodes abstraites soient redéfinies.

Ci-après, un exemple d'une superclasse abstraite, dû à la présence en son sein d'une méthode abstraite, ainsi que deux sous-classes concrétisant cette même méthode de deux manière différentes.

abstract class O1 {
        abstract public void jexisteSansRienFaire();
    }
    class Fils01 : O1 {
        public override void jexisteSansRienFaire(){
            ....
        }
    }
    class AutreFils01 : O1
    {
        public override void jexisteSansRienFaire(){
            ....
        }
    }
l'addition de mot-clé override, lors de la concrétisation des méthodes abstraites. Le mot-clé virtual, lors de la déclaration des méthodes abstraites, n'est plus nécessaire (elles le sont automatiquement ), comme il l'est lors de la déclaration des méthodes, non plus abstraite mais concrète et à redéfinir.

Classe abstraite, une classe abstraite ne peut donner naissance à des objets. Elle a comme unique rôle de factoriser des méthodes et des attributs communs aux sous-classes. Si une méthode est abstraite dans cette classe, il sera indispensable de redéfinir cette méthode dans les sous-classes, sauf à maintenir l'abstraction pour les sous-classes et à opérer la concrétisation quelque niveaux en dessous.

Si la seule valeur des attributs différencie les objets entre eux, point besoins de sous-classes. L'usage des langues naturelles, en général, ne permet pas de distinguer le lien existant entre un objet et sa classe d'un côté, et le lien entre une sous-classe et sa superclasse de l'autre. Ma Renault, objet, est une Renault, classe. Une Renault, sous-classe, est une voiture,superclasse. La même expression « est une » est utilisée ici, alors qu'en programmation OO, ces deux contextes d'utilisation mènent à des développements logiciels très différents : simple instanciation d'objet dans le premier, mise en place d'une structure d'héritage à deux niveaux dans le second. Ne vous trompez pas et n'abusez pas d'héritage inutile. Il se doit d'alléger et non pas d'alourdir votre conception. Le gain de son apport, en clarté, économie , maintenance et extensibilité, doit être suffisamment important. Autrement n'y songez même pas et contentez-vous d'un seul niveau taxonomique.

Le polymorphisme en UML
Dans UML, toute classe ou méthode abstraite est indiquée en italique. Ici, la superclasse et la méthode de la classe sont, de fait, abstraites. Trois sous-classes concrètes redéfinissant la méthode faireMonNumero(), une méthode dont le corps d'instruction sera radicalement différent pour chacune des sous-classe. Une  « classe cliente » envoie indifféremment le message faireMonNumero() à tous les référents qu'elle possède comme attribut. Comme indiqué dans le diagramme, cet ou ces attributs seront typés par la superclasse. Il peut s'agir d'un et un seul référent , typé statiquement d'une unique manière, mais qui lors de l'exécution du message, peut endosser plusieurs types dynamiques différents. Cela peut être un tableau de référents, qui lors de l'envoi d'un même message, en boucle sur tous les éléments du tableau , donnera lieu à des exécutions différentes.

Aucun objet n'est ici encore créé, sauf un tableau de référent. Il n'y a donc, à ce stade, pas de tentatives, qui seraient rejetées à la compilation, de création d'objet d'une classe abstraite (la superclasse ici). Les référents pointerons vers des objets, qui eux, lors de leur création, seront de type dynamique, type correspondant à une des sous-classes héritant de la superclasse. L'opération de création d'objet se fera à partir des sous-classes, bien concrètes cette fois. Chaque objet sera donc typé statiquement par son référent superclasse, et typé dynamiquement par sa sous-classe.

Il n'y aurait aucun problème à approfondir l'arbre d'héritage, et à laisser, nonobstant le lien client-serveur entre la classe cliente et la superclasse, la manière dont le message serait exécuté être définie bien plus bas dans l'héritage. Plusieurs couches de classes abstraites peuvent précéder l'arrivée, tout en bas, des classes concrètes. Rappelez vous qu'à entendre certains gourous de l'OO, les superclasses ne devraient être, en principe, qu'abstraites. Principe discutable, nullement en jetant un simple coup d'oeil au monde qui nous entoure.

Aucun commentaire: