2012-04-06 1 views
2

J'essaie de comprendre la situation d'un polymorphisme/héritage en C#.Polymorphisme: bien faire les choses

Ce que j'est en ce moment ces classes:

Lease (the base class containing the general data) 
PrivateLease (inheriting from the Lease class) 
BusinessLease (inheriting from the Lease class) 

Ce que je veux atteindre est le suivant:

Lease lease = new PrivateLease(); 

Cela fonctionne au moment, mais je ne suis pas en mesure d'accéder aux propriétés sur l'objet PrivateLease lorsque vous faites cela. Au moins pas sans coulée d'abord l'objet Lease à un objet .

J'aimerais que l'objet Lease soit l'objet général d'un objet PrivateLease ou BusinessLease qui contient toutes les données pour l'un des objets. Puis, lors de l'insertion/la mise à jour/la suppression de la base de données, je vais demander quel type est le premier à déterminez les tables dans lesquelles insérer les données.

J'ai un étrange sentiment que ce qui précède n'est pas la bonne approche pour résoudre ce problème. Quelqu'un at-il des indices à ce sujet? :-) J'ai cherché sur google et lu dans mes livres de programmation et tout le monde suggère cette approche d'avoir une classe de base et d'en hériter ensuite aux autres classes.

Toute aide/indice est grandement appréciée!

Merci d'avance.

EDIT

aurait dû élaboré un peu ce depuis le début, je suis désolé pour ça!

Les classes mentionnées ci-dessus ne font que conserver des données de l'interface utilisateur de ma solution ASP.NET pour effectuer des opérations CRUD contre la base de données via une couche d'accès aux données. Donc, basiquement, ces classes contiennent seulement un tas de propriétés pour contenir des données. À savoir:

public class Lease 
{ 
    public int Id { get; set; } 
    public bool IsActive { get; set; } 
    public string TypeOfRental { get; set; } 
    public string RentalPeriod { get; set; } 
    public DateTime TakeoverDate { get; set; }   
} 

public class PrivateLease : Lease 
{ 
    public string Floor { get; set; } 
    public string Side { get; set; } 
    public int FloorSize { get; set; } 
    public int NumberOfRooms { get; set; } 
} 

etc ..

Les PrivateLease et BusinessLease classes sont différentes en raison des différentes variables leaseing qui existe dans le monde réel :-)

Fondamentalement, je pouvais aller avec la deux objets distincts PrivateLease et BusinessLease, mais étant donné que le modèle impose qu'un objet Address peut contenir un ou plusieurs Lease s, ce n'est pas une option.

Pour moi, il me semble que je vais passer par un enfer majeur de coulée à la fois sur l'interface ASP.NET et sur le DAL? : -/

+0

Voir ma solution ici: http://stackoverflow.com/questions/8636568/c-sharp-property-inheritance-from-parent-class/8637104#8637104 –

Répondre

4

Ne pas décider (choisir une logique) sur la couche de consommateur, mais laisser décider par les classes elles-mêmes:

// or you ILease interface if a parent class will not contain any shared logic 
abstract class Lease 
{ 
    public abstract void Do(); 

    // example of shared logic 
    protected void Save(Lease l) { } 
} 

class PrivateLease : Lease 
{ 
    public override void Do() { // private logic here } 
} 

class BusinessLease : Lease 
{ 
    public override void Do() { // business logic here } 
} 

Utilisation:

Lease l = ... 
l.Do(); // execute the logic 

Vous pouvez créer une fabrique pour la création d'objets:

static class LeaseFactory<T> where T : Lease, new() // constraint to require default constructor existence 
{ 
    public static Leas Create() 
    { 
     return new T(); 
    } 
} 
+1

un peu malheureux nommant la méthode 'Bail' :) – NSGaga

+0

@NSGaga: D'accord. Renommé en juste 'Do()'. – abatishchev

+0

Salut abatishchev, merci beaucoup pour votre aide :-) Chose est que mes classes ne contiennent pas vraiment de logique par exemple, ils contiennent juste un tas de propriétés pour contenir des données (je suppose que vous pourriez les regarder comme un DTO, vraiment), donc il n'y aura pas de méthodes pour réellement surcharger dans cette situation :-) – bomortensen

3

Vous avez raison dans l'approche de base d'avoir une classe de base.

Ce que vous devez faire est de mettre toutes les propriétés communes dans la classe de base. Ensuite, si vous avez des règles métier différentes, celles-ci peuvent être implémentées avec des fonctions virtuelles, appelées polymorphiquement.

abstract class Lease 
{ 
    public int MonthlyCost {get;set;} 

    public string CustomerName {get;set;} 

    // Declare that all Leases have to have an IncreaseCost method. 
    public abstract void IncreaseCost(); 
} 

class PrivateLease : Lease 
{ 
    // Private leases are incremented by an absolute number (10). 
    public override void IncreaseCost() 
    { 
    MonthlyCost += 10; 
    } 
} 

class BusinessLease : Lease 
{ 
    // Business leases are incremented by 10%. 
    public override void IncreaseCost() 
    { 
    MonthlyCost *= 1.10; 
    } 
} 

// Somewhere in your code... 
Lease lease = new PrivateLease(); 

// This call is polymorphic. It will use the actual type of the lease object. 
lease.IncreaseCost(); 
+0

Salut Anders, merci beaucoup pour votre contribution :-) Donc, fondamentalement, je dois déclarer mes propriétés sur PrivateLease et BusinessLease en tant que chaîne virtuelle publique MyProperty {get; ensemble; }? – bomortensen

+0

S'il s'agit d'une simple propriété, vous ne devriez pas la rendre virtuelle. Il est assez rare qu'il y ait un avantage à faire des propriétés 'virtual'. D'un autre côté, les méthodes valent souvent la peine d'être «virtuelles». –

+0

@AndersAbel - 'PrivateLease' et' BusinessLease' devraient probablement hériter de 'Lease' avant de surcharger' IncreaseCost';) –

-1
Lease l = (Lease)sth; 

if (l is PrivateLease) 
{ 
    PrivateLease p = (PrivateLease)l;  
    //do private logic here 
} 
else if (l if BussinessLease) 
{  
    BussinessLease b = (BunessinessLease)l; 
    //do bussiness logic here 
} 
+2

Un conditionnel comme celui-ci est en fait un pas en arrière pour le polymorphisme. Jetez un oeil ici: http://martinfowler.com/refactoring/catalog/replaceConditionalWithPolymorphism.html et ici: http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism, entre autres. – David

+1

@David: D'accord. Utilisez le polymorphisme pour permettre aux classes de décider elles-mêmes de la logique à exécuter. – abatishchev

+0

Ce serait une violation du principe ouvert/fermé pour ceux qui sont fans de SOLID. – BlackWasp

1

Dans le OOD moderne, vous pouvez utiliser interfaces, pour cette situation.

Edit:

À mon avis, pour éviter la coulée, vous pouvez avoir plusieurs interfaces à des fins multiples. alors PrivateLease et BusinessLease peuvent implémenter ceux qui conviennent.

interface IWrite 
{ 
    string Data { get; set; } 
    void Write(); 
} 

interface IRead 
{ 
    string Data { get; set; } 
    void Read(); 
} 

public class Lease 
{ 
    //.. 
} 

public class PrivateLease : Lease, IWrite, IRead 
{ 
    // other implementations 
    public string Data { get; set; } 
    public void Read() 
    { 
     //.. 
    } 
    public void Write() 
    { 
     //.. 
    } 
} 
public class BusinessLease : Lease, IRead 
{ 
    // other implementations 
    public string Data { get; set; } 
    public void Read() 
    { 
     //.. 
    } 
} 
+0

Aucun exemple ...... –

+0

Salut Mouliyan, merci pour votre aide :-) Pourtant, si je fais ceci: ILease lease = new PrivateLease(); Je ne pourrai pas accéder aux propriétés de l'objet PrivateLease si elles ne sont pas implémentées via l'interface ILease, ce qui ne m'intéresse pas car la classe Lease devrait contenir toutes les données générales pour les objets de type Lease. – bomortensen

+0

you peut implémenter différentes interfaces pour les propriétés associées. – Mouliyan

0

Dans la classe Lease, ajoutez la méthode virtuelle appelée DBUpdate et dans les deux classes dérivées, et remplacez-la par.

Disons que une classe utilitaire a LeaseDBOperation méthode ressemble à ceci:

public static void LeaseDBOperation (Lease anylease) 
{ 

    anyleaase.DBUpdate(); 
} 

vous pouvez appeler cette méthode comme:

var pl = new PrivateLease(); 
..set all the properties of **pl** 
//call this for db operations : 
Utility.LeaseDBOperation(pl) 

Ici méthode LeaseDBOperation, si elle est basée sur l'envoi de type, DBUpdate méthode de la classe requise sera appelée.

+0

Salut Dhananjay, merci pour votre contribution :-) C'est plus ou moins comment je le fais maintenant. Avoir un CreateLease (bail bail) sur ma liste d'accès client où je crée le bail dans la base de données. Ma principale "question" sur ce point est que je vais devoir vérifier l'objet de bail est soit une PrivateLease ou une BusinessLease avant d'insérer quelque chose dans la base de données .. – bomortensen

+0

en fait pas. La méthode anyleaase.DBUpdate() s'en chargera. La méthode DBUpdate() est écrite dans les deux classes de bail (bail privé et commercial.). vous n'avez pas à vous soucier de celui que vous mettez à jour .. – Dhananjay