2009-07-27 7 views
3

Supposons que j'ai une définition pour une porte:OOD et sujet-objet confusion

class Door 
{ 
    public void Lock() 
    { 
     // lock the door 
    } 
} 

Cela semble faire du sens pour moi, au moins pendant un certain temps. Mais maintenant, je ne suis pas si sûr. Si j'avais un objet Personne qui voulait verrouiller une Porte, il appellerait aDoor.Lock(). Mais dans la vraie vie, nous ne verrouillons pas les portes en disant à la porte de se verrouiller.

Il semblerait qu'un modèle plus précis de la situation serait la personne capable de modifier directement l'état de l'air, à condition qu'il ait suffisamment de puissance pour verrouiller les portes. Par exemple, aCat ne devrait pas pouvoir définir aDoor.IsLocked = true. Je pouvais voir comment faire cela avec des propriétés, si elles pris en charge les paramètres:

class Person 
{ 
    public void LockDoor(Door door) 
    { 
     door.IsLocked(this) = true; 
    } 
} 

class Door 
{ 
    bool isLocked; 

    public bool IsLocked(Person person) 
    { 
     set 
     { 
      if(person != null) // ensure there is a real person trying to lock the door 
      { 
       this.isLocked = value; 
      } 
     } 
    } 
} 

static void Main() 
{ 
    Person personFromThinAir = new Person(); 
    Door doorFromThinAir = new Door(); 
    personFromThinAir.LockDoor(doorFromThinAir); 
} 

Au lieu de cela, ce que nous pouvons faire est la suivante:

class Person 
{ 
    public void LockDoor(Door door) 
    { 
     door.SetLocked(this, true); 
    } 
} 

class Door 
{ 
    bool isLocked; 

    public void SetLocked(Person person, bool locked) 
    { 
     if(person != null) 
     { 
      this.isLocked = locked; 
     } 
    } 
} 

Il est évident que ces deux classes sont fortement couplés et les deux aurait probablement interfaces extraites dans le code réel, mais ce n'est pas ce que je veux dire. Ma question est, est-ce une meilleure façon de modéliser la relation entre les deux objets? Y a-t-il un moyen encore meilleur que celui-ci? Plus j'y pense, moins j'ai le sens de aDoor.Lock() que je peux faire; il semble violer la conception orientée objet.

Répondre

9

Bien que la personne « verrouille » la porte, en réalité, la personne est BASCULEMENT (ou monopolise) sur un élément de la porte (la poignée de verrouillage) et que la manipulation provoque le verrouillage de la porte. Vous pouvez penser à ceci où, bien que la personne bouge le pêne dormant, le pêne dormant est ce qui verrouille la porte - pas la personne. Donc une meilleure représentation pourrait être qu'une porte a un verrou, et la personne appelle lock.lock(), qui verrouille ensuite le verrou (verrouillé).

La prémisse de base ici est que, bien que la personne manipule le verrou, c'est externe (l'appel de la fonction). Les changements internes de la serrure (le code à l'intérieur de la fonction) est ce qui provoque le verrouillage de la porte. La personne ne retire pas la poignée et ne manipule pas l'intérieur pour verrouiller la porte à chaque fois - ils basculent simplement d'un état à l'extérieur et s'attendent à ce que la machinerie interne la manipule.

+0

bien dit - tapé plus vite que moi! –

+0

Il est utile d'avoir essayé d'enseigner ce concept pendant environ 4 ou 5 ans;) Permettez-moi de vous dire, vous trouverez finalement beaucoup d'exemples pour essayer d'obtenir le concept de POO à travers – aperkins

6

La POO n'est pas vraiment une question de modélisation de la façon dont les choses fonctionnent dans le «monde réel». C'est plus sur la gestion de la complexité. Considérant ceci, il est parfaitement acceptable que la porte se verrouille. Même dans le monde réel, une personne qui verrouille une porte n'a pas besoin de savoir quoi que ce soit sur le fonctionnement de la serrure, à part tourner le bouton ou la clé. Cacher les détails d'une idée complexe derrière une abstraction est ce qui rend la POO si utile. Les abstractions que vous utilisez diffèrent avec le domaine du problème. Dans l'exemple que vous avez donné la personne ne devrait pas besoin de savoir quoi que ce soit au sujet de la porte autre que la façon de le faire fonctionner:

class Door 
{ 
    public bool Open(){} 
    public bool Close(){} 
    public void Lock(){} 
    public void Unlock(){} 
} 
0

Le problème de conception le plus intéressant ici est de savoir comment gérer le couplage entre le casier et le lockee car il y a des exigences qui doivent être respectées pour que le verrouillage/déverrouillage soit autorisé. Je regarde cette question et j'imagine un jeu où un joueur peut parfois être un humain mais d'autres fois être un chat (selon l'exemple donné), et peut-être is_human est la seule condition requise pour le verrouillage/déverrouillage. Mais vous pouvez également avoir des portes qui nécessitent que la clé correspondante soit dans la possession du joueur pour que le verrouillage/déverrouillage se produise. Si oui, vous devez ajouter cela aux critères. Peut-être que certaines portes ne peuvent être verrouillées que d'un côté et non de l'autre, de sorte que l'emplacement du joueur doit être ajouté aux critères. Vous pourriez également ajouter une compétence lockpicking que certains joueurs pourraient avoir (cambrioleurs, sans doute) pour leur permettre d'avoir une chance de déverrouiller (mais pas de verrouiller) une porte même s'ils n'avaient pas la clé. Etc.

On peut imaginer une conversation entre les objets comme:

Player: "I am trying to unlock you." 
Lock: "Do you meet requirement A?" 
Player: "Yes" 
Lock: "Do you meet requirement B?" // Only some doors would ask this. 
Player: "Yes" 
Lock: "OK, you succeed. I am unlocked!" 

Mais, vous ne voulez probablement pas d'exposer les champs impliqués publiquement ou encombrer l'interface du joueur vu par des objets qui ne ont pas besoin de connaître les exigences de verrouillage/déverrouillage. Je ne suis pas un programmeur C#, et ça fait un moment que j'ai fait Java, mais je pense qu'une approche en Java qui peut aussi s'appliquer en C# serait que l'objet Player passe une instance d'une classe interne lock_unlock_credentials en tant que paramètre des méthodes get_locked/get_unlocked de l'objet Door (ou de l'objet Lock comme suggéré). L'objet lock_unlock_credentials aurait des méthodes de rappel qui, en tant que classe interne du joueur, pourraient accéder aux champs pertinents du lecteur. objet, mais ces champs ne seraient autrement pas exposés en dehors de Player. L'objet verrouillable pourrait alors utiliser ces méthodes de rappel pour vérifier si les exigences dont il se soucie sont respectées. Vous ne pouvez pas éviter le couplage résultant des exigences, mais cela conserve les détails internes à l'interaction entre le Lecteur et l'objet Verrouillable.

Vous ne savez pas si la même approche de classe interne s'applique à C#, mais en présentant cela comme quelque chose à penser.