2009-10-12 7 views
0

Vous cherchez des conseils sur la façon de structurer/architecturer une application et j'ai quelques difficultés. N'hésitez pas à ne pas limiter les réponses aux détails techniques, car je ne suis pas sûr de faire les choses de la manière la plus efficace. Je donne des exemples dans VB.NET, mais n'hésitez pas à utiliser C#, car c'est notre langue cible officielle. Je connais juste mieux vb. Nous utilisons également Visual Studio 2008.Héritage/Architecture

Donc, le scénario: Nous sommes en train d'écrire une application web qui (nous l'espérons) sera personnalisable pour plusieurs clients. Par souci de concision et de ne pas donner la ferme, disons que c'est une application de personnel. Donc, je vais avoir une classe de base Person. Cela aura des méthodes très générales seulement. Il a une propriété publique Nom dans la classe Class1.

Juste pour l'amour arguments, je vais maintenant créer un nouveau projet/assemblage Person.Employee

Maintenant, depuis que je pourrais vouloir vendre cette application aux agences de mannequins ou des entreprises de construction, peut-être que je veux ajouter un peu de très propriétés impaires. CheekStructure ou CanOperateHeavyMachinery

Alors, je vais créer de nouveaux projets en studio appelé Person.Employee.TinasModeling & Person.Employee.TomsConstructionCompany qui contiendra le code pour une entreprise spécifique uniquement.

Vous pouvez supposer que chacun de ces assemblys contiendra UNIQUEMENT une logique métier appropriée au niveau de l'assemblage dans la hiérarchie. Rappelez-vous, ceci est destiné à être une application personnalisée pour de nombreuses entreprises différentes, mais toutes traitant avec le personnel. C'est pourquoi je suis venu avec ce modèle. Si nous trouvons un bug dans un niveau inférieur, je veux juste pouvoir le réparer et expédier un dll ou un 2. Cette structure est très fortement ciblée sur nous et peut-être avoir 20 applications personnalisées ou plus. La distribution et la maintenance sont les préoccupations de PARAMOUNT ici. Il n'y a pas beaucoup de développeurs. Plus que moi, mais moins de 3 -grin-.

Maintenant, le problème.

Par souci de simplicité, j'ai Class1 en personne.

Dans mon application web, j'ai une référence à Person.Employee.TinasModeling Ce projet d'application web est juste pour Tinas Modeling.

Si je
Imports Person.Employee.TinasModeling
...

Dim cette As New Class1
this.Name = "une valeur"

Cela ne compilera pas à moins d'avoir une référence à la personne aussi.

Question 1. Ai-je vraiment besoin d'une référence à la personne de la classe de base (et probablement aussi à Person.Employee), ou y a-t-il une façon de s'en passer? Je ne veux pas que quelqu'un crée accidentellement des classes aux niveaux inférieurs de la chaîne d'héritage. Je ne suis pas sûr de vouloir les créer à des niveaux inférieurs, mais peut-être que mon problème est sans intérêt?

Question 2. Est-ce la meilleure façon d'architecturer cela?S'il vous plaît rappelez-vous, Maint et Distribution sont les préoccupations primaires ici. Image trouvant un bug à un niveau bas et devant ouvrir 20 solutions, construire chacune, tester (même si automatisé), construire et distribuer. Je veux vraiment la capacité d'envoyer 1 Dll (ou peut-être celui qui a été mis à jour, et les dépendants aussi?) Et être fait, si cette dll de niveau inférieur passe ses tests

Si je dois avoir des références à tous les niveaux inférieurs de l'arbre de l'héritage, peut-être que je devrais simplement mettre tout cela en une seule assemblée sous différents espaces de noms?

Cripes, j'espère que c'est assez clair. J'ai cherché google toute la journée pour des échantillons d'héritage en essayant de trouver quelque chose d'utile. Espérons que quelqu'un ici puisse nettoyer le brouillard de mon cerveau.

Merci à l'avance, Bob

Répondre

0

En tant que principe général, les classes à la racine de l'arbre doivent tous être abstrait, car ils sont tous incomplètes.

Lorsque seuls les types spécifiques à l'application client individuelle sont concrétisés, votre problème de créer par inadvertance d'autres classes disparaît.

1

Cela semble être un bon candidat pour utiliser l'injection de dépendances - Pour commencer, jetez un oeil à this example sur le site Spring.NET. Toutes mes excuses pour cette brève réponse, mais je peux élaborer ce soir quand j'ai plus de temps pour m'asseoir et coder un exemple rapide plus pertinent pour votre message.

EDIT: Ok premier permet d'introduire deux objets enfants, TinasModeling.Model et BobTheBuilder.Builder

public class Model : IPerson 
{ 
    private bool canAct; 
    public bool CanAct 
    { 
     get { return canAct; } 
     set { canAct = value; } 
    } 

    private double weight; 
    public double Weight 
    { 
     get { return weight; } 
     set { weight = value; } 
    } 

    public Model() 
    { 
    } 

    public bool PayPerson(double Amount) 
    { 
     if (canAct) 
      RequestFilmBoxOfficeRevenue(); 
     Pay(); 
    } 

    public bool NewJobRequest() 
    { 
     SendPhotoPortfolioToClient(); 
     SendJobLocationToModel(); 
     if (canAct) 
      NotifyFilmCrew(); 
     if (weight < 40.00) 
      ContactNutritionist(); 
    } 
} 

public class Builder : IPerson 
{ 
    private bool canOperateDigger; 
    public bool CanOperateDigger 
    { 
     get { return canOperateDigger; } 
     set { canOperateDigger = value; } 
    } 

    private double certifiedBuilder; 
    public double CertifiedBuilder 
    { 
     get { return certifiedBuilder; } 
     set { certifiedBuilder = value; } 
    } 

    public Builder() 
    { 
    } 

    public bool PayPerson(double Amount) 
    { 
     ReuqestTimeSheet(); 
     Pay(); 
    } 

    public bool NewJobRequest() 
    { 
     SendBluePrintsToBuilder(); 
     if (!certifiedBuilder) 
      RequestLegalAdvice(); 
     if (canOperateDigger) 
      RequestDrivingPermit(); 
    } 

Les deux classes sont mises en œuvre dans des projets séparés - ils ne doivent pas être, mais ils sont pour raisons que je vais expliquer plus tard. Comme vous pouvez le voir, les deux font les choses différemment, mais ont une chose en commun: ils implémentent l'interface IPerson.

public interface IPerson 
{ 
    bool PayPerson(double Amount); 
    bool NewJobRequest(); 
} 

Cette interface est implémentée, encore une fois, dans un ensemble séparé que les deux objets mentionnés ci-dessus et donc notre enfant des objets références de cette assemblée, permet de l'appeler BOL (Layer Business Object). Dans le BOL nous mettons en œuvre une autre classe appelée PersonController

public class PersonController 
{ 
    private IPerson thePerson; 
    public IPerson ThePerson 
    { 
     get { return this.thePerson; } 
     set { this.thePerson = value; } 
    } 

    public PersonController() 
    { 
    } 

    public bool PayPerson(double Amount) 
    { 
     return this.thePerson.PayPerson(Amount); 
    } 

    public bool NewJob() 
    { 
     return this.thePerson.NewJobRequest(); 
    } 
} 

La chose la plus importante à noter à propos PersonController est la propriété theperson. Cela va être notre point d'injection de dépendance. Il convient de souligner à ce stade que la couche BOL est complètement découplée de tout objet enfant. C'est une caractéristique importante qui va donner beaucoup de flexibilité au moment du déploiement et de la maintenance.

Maintenant, nous utilisons et configurons ce que nous avons construit jusqu'à présent. Notre application ne fait référence qu'à la couche BOL (découplage aussi notre application principale de tous les objets enfants). Dans notre application principale, nous utilisons l'ensemble Spring.NET Spring.Core et dans un fichier app.config on ajoute ce qui suit (pour une meilleure lisibilité, j'ai omis la balise configSections)

<spring> 
<context> 
    <resource uri="config://spring/objects"/> 
</context> 
<objects xmlns="http://www.springframework.net"> 
    <description>An example that demonstrates simple IoC features.</description> 
    <object name="Person" type="BOL.BOL.PersonController, BOL.BOL"> 
    <property name="ThePerson" ref="Person"/> 
    </object> 
    <object name="Person" type="BobTheBuilder.BobTheBuilder.Builder, BobTheBuilder.BobTheBuilder"> 
    </object> 
</objects> 

tout le monde est OK espoir avec moi jusqu'à maintenant - le premier élément d'objet fait référence à la classe qui nécessite l'injection de dépendance, dans notre cas le PersonController. L'élément de propriété enfant fait référence au point d'injection de dépendance dans PersonController ou, dans notre cas, à la propriété ThePerson.L'attribut ref de cet élément fait référence à notre deuxième élément objet.

Le deuxième élément d'objet définit l'objet enfant que nous souhaitons injecter lors de l'exécution (par exemple, TinasModeling.Model ou BobTheBuilder.Builder).

Enfin le code qu'il met tous ensemble

static void Main(string[] args) 
    { 
     IApplicationContext ctx = ContextRegistry.GetContext(); 
     PersonController person = (PersonController)ctx.GetObject("Person"); 

     // Ready to use person with implementation specified in config 
     person.NewJob(); 
     person.PayPerson(); 
    } 

Donc, ce instanciera PersonController basé sur la façon dont nous avons configuré « Personne » dans notre app.config. Donc, la réponse à la première question est non (enfin au moins comme indiqué ci-dessus) - vous séparez complètement vos implémentations de base. La réponse à la question 2 (Est-ce la meilleure façon d'architecturer ce) est probablement un peu subjective - mais avec la distribution et la maintenance étant votre principale préoccupation à mon avis, la conception ci-dessus répond à vos besoins parce que les assemblages sont en train de faire pour le levage lourd est complètement découplé.

Espérons que je me suis bien expliqué.