Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

classe mère -> forcer l'implémentation de propriétés ou variables membres

11 réponses
Avatar
Messenger of the red snake mountain
Bonjour à tous,

J'ai une classe parente 'Entite' exposant certaines méthodes génériques
ainsi que des méthodes dont je souhaite forcer l'implémentation par les
classes enfants.

J'ai donc fait usage de méthodes abstraites et utilisé les signatures
suivantes:

protected abstract string GetInformations();

Ce qui marche exactement comme je le souhaite.


Cependant, j'aimerais également ajouter des variables membres (string)
ou même des propriétés (si pas possible) statiques dont je peux par le
même mécanisme "forcer" l'implémentation par la classe enfant.

J'ai donc tenté d'écrire ceci:

public abstract static string Module;

Mais comme vous l'aurez deviné, c'est refusé (un membre statique ne
peut être déclaré comme override, virtual ou abstract).

Je sais que je peux déclarer une version dans la classe et ensuite utiliser
override dans la classe enfant mais l'IDE ne forcera pas le dévelopeur
à le faire.

Question: comment forcer l'implémentation de méthodes ou propriétés
statiques au sein de la classe enfant?

Merci d'avance pour vos propositions = )

.antoine





--




------------oOoo---Ôô----ooOo---------------------------
Antonio FONTES (well, me, actually)
http://www.nxtg.net/saphyr/ (tout et rien en français)
http://www.nxtg.net/is/ (blog - développeur web)
E-mail: prenom.nom@mondomaine.net
-------------------------------------------------------------

10 réponses

1 2
Avatar
Faust
un truc comme ça, ça marche pas:

protected abstract string GetModule();

public static string Module;
{ get { return GetModule(); } }

?

Bonjour à tous,

J'ai une classe parente 'Entite' exposant certaines méthodes génériques
ainsi que des méthodes dont je souhaite forcer l'implémentation par les
classes enfants.

J'ai donc fait usage de méthodes abstraites et utilisé les signatures
suivantes:

protected abstract string GetInformations();

Ce qui marche exactement comme je le souhaite.

Cependant, j'aimerais également ajouter des variables membres (string)
ou même des propriétés (si pas possible) statiques dont je peux par le
même mécanisme "forcer" l'implémentation par la classe enfant.

J'ai donc tenté d'écrire ceci:

public abstract static string Module;

Mais comme vous l'aurez deviné, c'est refusé (un membre statique ne
peut être déclaré comme override, virtual ou abstract).

Je sais que je peux déclarer une version dans la classe et ensuite utiliser
override dans la classe enfant mais l'IDE ne forcera pas le dévelopeur
à le faire.

Question: comment forcer l'implémentation de méthodes ou propriétés
statiques au sein de la classe enfant?

Merci d'avance pour vos propositions = )

.antoine



--
Mephitiquement votre,
Faust
ICQ #161252577
Avatar
Dimitri Travailloux
Et les Interfaces tu y as pensé ?

Cela pourrait répondre à ton problème je suppose puisque une interface
définit des méthodes que les classes qui l'implémenteront devront utiliser.

@+
Dimitri
Avatar
Messenger of the red snake mountain
> Et les Interfaces tu y as pensé ?


oui, bien sûr = )

Cela pourrait répondre à ton problème je suppose puisque une interface
définit des méthodes que les classes qui l'implémenteront devront utiliser.


A première vue l'IDE me refuse la déclaration de membres statiques
dans l'interface.

.antoine
Avatar
Zazar
Bonjour,

Cependant, j'aimerais également ajouter des variables membres (string)
ou même des propriétés (si pas possible) statiques dont je peux par le
même mécanisme "forcer" l'implémentation par la classe enfant.

J'ai donc tenté d'écrire ceci:

public abstract static string Module;

Mais comme vous l'aurez deviné, c'est refusé (un membre statique ne
peut être déclaré comme override, virtual ou abstract).



(texte pas compris mais à priori pas important)

Question: comment forcer l'implémentation de méthodes ou propriétés
statiques au sein de la classe enfant?



C'est impossible et c'est normal :

Les membres statiques sont associés à un type.
Gardons ça en tête et supposons que ce soit possible :

public class A {
public abstract static string Module;
}

public class B : A {
public override static string Module;
}

L'héritage sert à manipuler des objets possédants des propriétés communes.
Déclarons donc un objet de type A et utilisont la propriété commune à tous
les objets de type A :
public void MyMethod(A a) {
DoSomething(a.Module); //Ca n'a pas de sens car Module est static et donc
associé à un type pas à un objet.
}

Déclarer un membre static et abstract/virtual n'a donc pas de sens.
Si vous en avez besoin, c'est que vous avez à priori un problème de
conception (sauf si vous voulez utilisez des opérateurs qui sont statiques,
mais c'est un autre débat).
Dans quelle situation estimez vous en avoir besoin ?

--
Zazar
Avatar
Ambassadeur Kosh
> L'héritage sert à manipuler des objets possédants des propriétés
communes.
Déclarons donc un objet de type A et utilisont la propriété commune à tous
les objets de type A :
public void MyMethod(A a) {
DoSomething(a.Module); //Ca n'a pas de sens car Module est static et donc
associé à un type pas à un objet.
}

Déclarer un membre static et abstract/virtual n'a donc pas de sens.
Si vous en avez besoin, c'est que vous avez à priori un problème de
conception (sauf si vous voulez utilisez des opérateurs qui sont
statiques,
mais c'est un autre débat).
Dans quelle situation estimez vous en avoir besoin ?



pour ce qui concerne son cas de figure, j'imagine le pire, mais suite à
notre reflexion comunne sur la genericité, je m'interroge... c'était comment
en smalltalk , je me souviens plus ?
Avatar
Zazar
Bonsoir,

pour ce qui concerne son cas de figure, j'imagine le pire, mais suite à
notre reflexion comunne sur la genericité, je m'interroge... c'était


comment
en smalltalk , je me souviens plus ?



J'ai fait autant de smalltalk que d'eiffel, je ne peux donc pas vous
répondre.

--
Zazar
Avatar
Messenger of the red snake mountain
> Dans quelle situation estimez vous en avoir besoin ?



J'ai des classes entité-relation encapsulant la persistance avec les tables
de la base de données.

Ex:
------------------------------------------------------
//création d'un nouveau compte
Compte c = new Compte();
c.Proprietaire = "moi";
c.DateCreation = DateTime.Now;
c.SoldeInitial = 2000;
c.Insert();

//recherche des comptes dont le solde initial est à 2000
ArrayList alAccounts = Compte.FindBySoldeInitial(2000);
foreach(Compte c in alAccounts)
{
//...
}

//recherche du compte de référence '1000-AA'
Compte c = Compte.FindByRef("1000-AA");
------------------------------------------------------

Comme vous pouvez le constater, les méthodes dites 'Finder Methods' (ici,
FindByRef et FindBySoldeInitial) sont à accès statique. Il ne serait
conceptuellement pas correct d'écrire ceci:

ArrayList alAccounts = new Compte().FindBySoldeInitial(2000);

Cette application ne devait à la base qu'être un "util" minimal est peu fonctionnel.
Aujourd'hui mon boss veut en vendre une version améliorée et nous nous
retrouvons dessus à plusieurs développeurs.

Je souhaite contractualiser l'implémentation de classes entités et forçant
l'implémentation de deux Finders minimaux:
- FindByRef //retourne l'instance trouvée grâce à la valeur d'une clé primaire
- FindAll() //retourne la collection de tous les éléments

en méthodes statiques..

Ni plus, ni moins. J'espère avoir clairement répondu à votre question = )


.antoine
Avatar
Zazar
Bonjour,

J'ai des classes entité-relation encapsulant la persistance avec les


tables
de la base de données.

Ex:
------------------------------------------------------
//création d'un nouveau compte
Compte c = new Compte();
c.Proprietaire = "moi";
c.DateCreation = DateTime.Now;
c.SoldeInitial = 2000;
c.Insert();

//recherche des comptes dont le solde initial est à 2000
ArrayList alAccounts = Compte.FindBySoldeInitial(2000);
foreach(Compte c in alAccounts)
{
//...
}

//recherche du compte de référence '1000-AA'
Compte c = Compte.FindByRef("1000-AA");
------------------------------------------------------

Comme vous pouvez le constater, les méthodes dites 'Finder Methods' (ici,
FindByRef et FindBySoldeInitial) sont à accès statique. Il ne serait
conceptuellement pas correct d'écrire ceci:

ArrayList alAccounts = new Compte().FindBySoldeInitial(2000);

Cette application ne devait à la base qu'être un "util" minimal est peu


fonctionnel.
Aujourd'hui mon boss veut en vendre une version améliorée et nous nous
retrouvons dessus à plusieurs développeurs.

Je souhaite contractualiser l'implémentation de classes entités et forçant
l'implémentation de deux Finders minimaux:
- FindByRef //retourne l'instance trouvée grâce à la valeur d'une


clé primaire
- FindAll() //retourne la collection de tous les éléments

en méthodes statiques..

Ni plus, ni moins. J'espère avoir clairement répondu à votre question = )



Oui et non. Je n'ai pas été assez précis : comment vous utiliseriez
l'héritage si il existait ? Donnez moi par exemple, la classe Finder de
base, les 2 finders filles et un code qui fonctionnerait si l'héritage
existait.

Sinon 2 remarques :
Si je comprends bien, votre classe Compte posséde un champ statique qui


est une collection quelconque contenant l'ensemble des Compte ? Si c'est
bien ça, c'est une mauvaise idée : le jour où vous aurez besoin de 2
collections, vous ferez comment ? Séparez la collection des données.
Vous réinventez la roue : utilisez un dataset (de préférence fortement


typé) : vous verrez : vous écrirez moins de code et vous aurez beaucoup
plus de fonctionnalités.

--
Zazar
Avatar
Messenger of the red snake mountain
> > Ni plus, ni moins. J'espère avoir clairement répondu à votre question = )



Oui et non. Je n'ai pas été assez précis : comment vous utiliseriez
l'héritage si il existait ? Donnez moi par exemple, la classe Finder de
base, les 2 finders filles et un code qui fonctionnerait si l'héritage
existait.



Quelque chose de ce genre:
---avec interface-start--------------------------------------------------
public interface IEntity
{
long Insert();
long Update();
long Delete();

static ArrayList FindAll();
static IEntity FindByRef(long aRef);
}

public class Client : IEntity
{
//implémentations forcées des méthodes de l'interface
//mais actuellement VS refuse les signatures statiques dans l'interface
}
---avec interface-stop--------------------------------------------------

---avec classe héritée-start--------------------------------------------------
public class Entity
{
public abstract long Insert();
public abstract long Update();
public abstract long Delete();

public abstract static ArrayList FindAll();
public abstract static IEntity FindByRef(long aRef);
}

...et utiliser des 'orverride' dans les classes filles héritant de Entity.
---avec classe héritée-stop--------------------------------------------------

Bref, j'aimerais juste dire : "mes filles doivent implémenter deux méthodes
statiques".


Sinon 2 remarques :
> Si je comprends bien, votre classe Compte posséde un champ statique qui
est une collection quelconque contenant l'ensemble des Compte ? Si c'est
bien ça, c'est une mauvaise idée : le jour où vous aurez besoin de 2
collections, vous ferez comment ? Séparez la collection des données.
> Vous réinventez la roue : utilisez un dataset (de préférence fortement
typé) : vous verrez : vous écrirez moins de code et vous aurez beaucoup
plus de fonctionnalités.



Oui et non, un exemple court donne ceci (je fais omission de tous les contrôles
d'integrité, propriétés à la place de membres publics, blocs try/catch, etc pour
augmenter la lisibilité):

public class Client
{
public long id;
public long domain_ref; //référence à un ensemble de clients (domaine)
public string nom;

public long Insert()
{
this.id = DatabaseUtils.GenerateUniqueID();
sql = " INSERT INTO clients VALUES (@id, @domain_ref, @nom) ";

//je saute la création et affectation des paramètres...

DatabaseUtils.ExecuteQueryWithParams(sql, params);
return(this.id);
}


public long Update()
{
sql = " UPDATE clients SET cli_domain_ref = @domain_ref, cli_nom = @nom WHERE id = @id ";

//je saute la création et affectation des paramètres...

DatabaseUtils.ExecuteQueryWithParams(sql, params);
return(this.id);
}


public long Delete()
{
sql = " DELETE FROM clients WHERE id = @id ";

//je saute la création et affectation des paramètres...

DatabaseUtils.ExecuteQueryWithParams(sql, params);
return(this.id);
}


//Finder PRIVE -> Contient des arguments pour tous les champs par
//lesquels il serait souhaitable d'effectuer un filtrage
private static ArrayList FindClients(long unId, long unDomaineRef, string unNom)
{

sql = " SELECT * FROM clients WHERE 1 = 1 ";

if(unId > 0)
{
//sql completée
sql += " AND cli_id = @id ";
//création du paramètre et ajout dans la collection
}

if(unDomaineRef > 0)
{
//sql completée
sql += " AND cli_domain_ref = @domain_ref ";
//création du paramètre et ajout dans la collection
}

if(!(unNom.Equals("")))
{
//sql completée
sql += " AND cli_nom = @nom ";
//création du paramètre et ajout dans la collection
}

//récupération des enregistrements
ArrayList al = new ArrayList();
IDataReader dr = DatabaseUtils.GetReaderWithParams(sql, params);
while(dr.Read())
{
Client c = new Client();
c.id = dr["cli_id"];
c.domain_ref = dr["cli_domain_ref"];
c.nom = dr["cli_nom"];
al.Add(c);
}

return(al); //contient un jeu d'enregistrements

}


//Maintenant je dispose d'une méthode statique entièrement paramétrable
//mais non accessible de l'extérieur.
//Je vais à présent fournir les méthodes publiques, dont les noms d'appels
//correspondent à des CAS D'UTILISATION identifiés lors de la conception
//à savoir: recherche par nom, recherche par référence et recherche des
//clients d'un domaine:
//On aura donc : FindByName, FindByRef, et FindByDomainRef.

public static Client FindByName(string unNom)
{
return((Client)(FindClients(0, 0, unNom)[0]));
}

public static Client FindByRef(long uneRef)
{
return((Client)(FindClients(uneRef, 0, "")[0]));
}

public static Client FindByDomainRef(long unDomaineRef)
{
return((Client)FindClients(0, unDomaineRef, ""));
}


//comme vous pouvez le constater, le temps nécessaire pour mettre en place
//les FINDER correspondant aux business cases ne prend que quelques
//secondes et tout est encapsulé au sein d'un seul Finder privé.

//cette classe 'Client' a peu de membres, mais je vous laisse imaginer le
//gain avec une entité du genre : "Membre" et des cas d'utilisations tels
//que:
// FindAllByDomainRef -> tous les membres d'un domaine
// FindByRef -> par référence
// FindByCredentials -> recherche par login et mot de passe
// FindByIPAdress -> dans le cas d'un système de reconnaissance IP
// FindByLogin -> recherche par login
// ...
}



Toujours réveillé ?

Bref, première remarque que l'on serait tenté de me faire (et on me l'a déjà faite):
pourquoi ne pas simplement rendre le Finder principal public et ne pas avoir
ainsi à implémenter tous les autres Finders ?

Ce choix découle de 2 besoins:
1) les librairies sont utilisées par d'autres développeurs possédant peu d'expérience
2) nous avons un système de spécifications inspiré de l'extreme programming,
des petites cartes cartonnées sur lequel figurent les cas d'utilisation.
Les méthodes découlant du cas d'utilisation sont standardisées: si le carton dit
"Find All members from a same domain", les deux développeurs chargés de
créer les librairies savent qu'il y aura un finder du genre FindAllByDomain(), etc.


En ce qui concerne votre proposition du dataset spécialisé.... j'y suis un peu
réfractaire et là c'est un choix plutôt politique et personnel. Un peu comme je choisis
d'utiliser des datareaders alors que d'autres développeurs très dépendants du
designer de VS ne savent même pas ce que c'est après une année de développement
orienté Dotnet.


.antoine

Si vous arrivez à cette ligne, merci d'avoir pris le temps de lire cette réponse ; )
Avatar
Zazar
Bonjour,

<snip>

Je ne me suis toujours pas fait comprendre.

Supposons que la syntaxe suivant soit correcte :

public interface IEntity
{
long Insert();
long Update();
long Delete();

static ArrayList FindAll();
static IEntity FindByRef(long aRef);
}

public class Client : IEntity
{


static ArryList FindAll() {...}

static IEntity FindByRef(long aRef) {...}

}

Et ma question serait alors: " Pouvez-vous donner un exemple de code qui en
tirerait partie ? " (Mais bon comme maintenant, ça doit faire 2 semaines que
vous avez réglé le problème, si vous voulez passer à autre chose, je ne vous
en tiendrais pas rigueur :) )


Sinon 2 remarques :
> Si je comprends bien, votre classe Compte posséde un champ statique qui
est une collection quelconque contenant l'ensemble des Compte ? Si c'est
bien ça, c'est une mauvaise idée : le jour où vous aurez besoin de 2
collections, vous ferez comment ? Séparez la collection des données.
> Vous réinventez la roue : utilisez un dataset (de préférence fortement
typé) : vous verrez : vous écrirez moins de code et vous aurez beaucoup
plus de fonctionnalités.



Oui et non, un exemple court donne ceci (je fais omission de tous les
contrôles
d'integrité, propriétés à la place de membres publics, blocs try/catch,
etc pour
augmenter la lisibilité):



<snip>

Ok, le champ statique dont je supposais l'existence est en fait une BDD :).


Toujours réveillé ?



J'ai du mal à garder les yeux ouverts, mais ce n'est pas à cause de vous.

Bref, première remarque que l'on serait tenté de me faire (et on me l'a
déjà faite):
pourquoi ne pas simplement rendre le Finder principal public et ne pas
avoir
ainsi à implémenter tous les autres Finders ?

Ce choix découle de 2 besoins:
1) les librairies sont utilisées par d'autres développeurs possédant
peu d'expérience
2) nous avons un système de spécifications inspiré de l'extreme
programming,
des petites cartes cartonnées sur lequel figurent les cas
d'utilisation.
Les méthodes découlant du cas d'utilisation sont standardisées: si le
carton dit
"Find All members from a same domain", les deux développeurs chargés de
créer les librairies savent qu'il y aura un finder du genre
FindAllByDomain(), etc.




Ok.


En ce qui concerne votre proposition du dataset spécialisé.... j'y suis un
peu
réfractaire et là c'est un choix plutôt politique et personnel. Un peu
comme je choisis
d'utiliser des datareaders alors que d'autres développeurs très dépendants
du
designer de VS ne savent même pas ce que c'est après une année de
développement
orienté Dotnet.


C'est dommage, ça apporte un gain de temps non négligeable (surtout avec un
VS.NET et une BDD déjà existante).

--

Zazar
1 2