2010-09-28 25 views
3

Disons que j'ai une hiérarchie de classes d'objets de domaine avec une classe de base et deux classes enfants, un niveau. Supposons que j'aie une liste de ces objets (liste de la classe de base) et que je veuille appliquer une certaine logique aux classes qui, selon moi, n'appartiennent pas réellement aux classes (par exemple, code de conception/interface utilisateur) .Choix de conception pour supprimer les instructions if-is

Quelles sont mes alternatives?

  1. Instruction if-is. Personnellement celui-ci ne devrait même pas être considéré comme une alternative mais je l'écris quand même.

  2. Polymorphisme. Celui-ci est en fait une alternative dans certains cas, mais avec mon exemple ci-dessus, je ne veux pas que mes classes contiennent des spécificités de l'interface utilisateur.

  3. Résolution d'une méthode logique via un conteneur de réflexion/IoC en fonction du type de l'objet.
    Ex. C#. Tapez type = typeof (ILogic <>). MakeGenericType (domainObject.GetType());
    J'aime vraiment celui-ci, je ne reçois aucun contrôle de temps de compilation si une implémentation est manquante pour une sous-classe, ou est-ce possible en quelque sorte?

  4. Modèle de visiteur. Ca va marcher mais ça semble un peu exagéré à appliquer sur une structure c'est seulement un niveau profond.

Quelqu'un a d'autres conseils ou astuces pour résoudre ce genre de problèmes?

Répondre

2

Bonne question. Le problème est qu'il existe de nombreuses solutions et la plupart fonctionneront.

Je travaille beaucoup avec MVC, une situation similaire se produit assez souvent. Surtout dans la vue, quand un rendu similaire doit se produire sur certaines vues ... mais n'appartient pas vraiment à la vue. Disons que nous avons la classe enfant ChildList qui s'étend BaseList. Ajouter une propriété uiHandler dans la classe enfant. Surchargez la fonction de rendu, disons toString(), et utilisez le uiHandler avec vos éléments d'interface utilisateur/conception spécifiques.

J'ai écrit un petit quelque chose, c'est en PHP ... mais vous devriez pouvoir vous faire une idée. Il vous donne la liberté de choisir comment vos objets seront affichés et la flexibilité d'utiliser des interfaces utilisateur spécifiques pour des objets spécifiques. Regardez le code ci-dessous, il semble que beaucoup mais int n'est pas si mal.

  • BaseList - votre classe
  • BaseListUIExtended de base - classe de base qui utilise l'interface utilisateur, se classe UI en option en tant que paramètre constructeur. En C# 4 vous pouvez utiliser optionnel, sinon utilisez 2 constructeurs.
  • UIBase - Interface pour les classes de l'interface utilisateur ...
  • UIChildSpecific - classe UI
  • ChildList - classe enfant qui peut utiliser l'interface utilisateur ou non, en raison de BaseListUIExtended paramètre du constructeur en option.

Définir l'interface

/** 
* Base UI interface 
*/ 
interface IUIBase { 

    /** 
    * Renders the Base Class 
    * 
    * @param UIBase $obj 
    * @return string 
    */ 
    public function render($obj); 

} 

Définir les classes de base, classe enfant

//************************************************************** 
// Define Base Classes 
//************************************************************** 
/** 
* Base Class 
*/ 
class BaseList { 

    /** 
    * List of items 
    * @var array 
    */ 
    protected $_items = array(); 

    /** 
    * Gets collection of items 
    * 
    * @return array 
    */ 
    public function getItems() { 
     return $this->_items; 
    } 

    /** 
    * Adds new item to the list 
    * @param object $item 
    */ 
    public function add($item) { 
     $this->_items[] = $item; 
    } 

    /** 
    * Displays object 
    */ 
    public function display() { 
     echo $this->toString(); 
    } 

    /** 
    * To String 
    */ 
    public function __toString() { 
     // Will output list of elements separated by space 
     echo implode(' ', $this->_items); 
    } 

} 

/** 
* Extended BaseList, has UI handler 
* This way your base class stays the same. And you 
* can chose how you create your childer, with UI or without 
*/ 
class BaseListUIExtended extends BaseList { 

    /** 
    * UI Handler 
    * @var UIBase 
    */ 
    protected $_uiHandler; 

    /** 
    * Default Constructor 
    * 
    * @param UIBase Optional UI parameter 
    */ 
    public function __construct($ui = null) { 

     // Set the UI Handler 
     $this->_uiHandler = $ui; 
    } 

    /** 
    * Display object 
    */ 
    public function display() { 
     if ($this->_uiHandler) { 
      // Render with UI Render 
      $this->_uiHandler->render($this); 
     } else { 
      // Executes default BaseList display() method 
      // in C# you'll have base:display() 
      parent::display(); 
     } 
    } 

} 

//************************************************************** 
// Define UI Classe 
//************************************************************** 

/** 
* Child Specific UI 
*/ 
class UIChildSpecific implements UIBase { 

    /** 
    * Overload Render method 
    * 
    * Outputs the following 
    *  <strong>Elem 1</strong><br/> 
    *  <strong>Elem 2</strong><br/> 
    *  <strong>Elem 3</strong><br/> 
    * 
    * @param ChildList $obj 
    * @return string 
    */ 
    public function render($obj) { 
     // Output array for data 
     $renderedOutput = array(); 

     // Scan through all items in the list 
     foreach ($obj->getItems() as $text) { 
      // render item 
      $text = "<strong>" . strtoupper(trim($text)) . "</strong>"; 
      // Add it to output array 
      $renderedOutput[] = $text; 
     } 

     // Convert array to string. With elements separated by <br /> 
     return implode('<br />', $renderedOutput); 
    } 

} 

//************************************************************** 
// Defining Children classes 
//************************************************************** 

/** 
* Child Class 
*/ 
class ChildList extends BaseListUIExtended { 
    // Implement's logic  
} 

test ...

//************************************************************** 
// TESTING 
//************************************************************** 

// Test # 1 
$plainChild = new ChildList(); 
$plainChild->add("hairy"); 
$plainChild->add("girl"); 
// Display the object, will use BaseList::display() method 
$plainChild->display(); 
// Output: hairy girl 

// Test # 2 
$uiChild = new ChildList(new UIChildSpecific()); 
$uiChild->add("hairy"); 
$uiChild->add("girl"); 
// Display the object, will use BaseListUIExtended::display() method 
$uiChild->display(); 
// Output: <strong>hairy</strong><br /><strong>girl</strong> 
+0

+1 pour Poilu Fille – demoncodemonkey

+0

Salut, ont à présent regardé votre exemple un peu plus et c'est une bonne solution, MAIS ... cela ne fonctionne pas dans des solutions plus complexes. Votre solution est élégante lorsque tous les éléments sont des chaînes ou d'autres types de valeur, mais si les objets de la liste sont des objets complexes qui nécessitent des méthodes de rendu encore plus complexes, cela ne sera pas si agréable. "dans la méthode render dans les implémentations IUIBase, c'est ce que je veux contourner. – Marcus

+0

@Marcus, d'après ma compréhension de votre question que vous vouliez rendre des objets, mais ne voulait pas garder UI/Design séparé. C'est exactement ce que fait mon exemple de code. Chaque classe aurait son propre gestionnaire d'interface utilisateur, cela séparera l'interface utilisateur de Logic (un peu comme 'view' et' controller' dans MVC). Les cordes ont été utilisées pour la simplicité. Vous pouvez créer 'Container' et positionner tous les objets (boutons, étiquettes, textboxes) avec le conteneur. De toute façon, vous devrez coder la logique UI/Design soit dans votre classe (code désordonné + difficile à maintenir) ou dans une sorte de gestionnaire d'interface utilisateur (code plus propre + plus facile à maintenir). – Alex