设计选择以删除if-is语句

时间:2010-09-28 14:31:15

标签: oop polymorphism typechecking

假设我有一个域对象的类层次结构,其中包含一个基类和几个子类,一个级别。

假设我有一个这些对象的列表(基类列表),我想将一些逻辑应用于我认为不属于类的类(例如,设计/ UI特定代码)。

我的替代方案是什么?

  1. If-is statement。就个人而言,这个甚至不应该被视为一种替代方案,但无论如何我都要写它。

  2. 多态性。在某些情况下,这个实际上是另一种选择,但在上面的示例中,我不希望我的类包含任何UI细节。

  3. 根据对象的类型,通过反射/ IoC容器解析一些逻辑方法 例如C#。类型type = typeof(ILogic<>)。MakeGenericType(domainObject.GetType());
    我真的很喜欢这个,我没有得到任何编译时间检查,但是如果子类缺少一个实现,或者这可能是某种方式?

  4. 访客模式。会起作用,但是在一个只有一层深的结构上应用有点矫枉过正。

  5. 任何人都有其他任何提示或技巧来解决这些问题吗?

1 个答案:

答案 0 :(得分:2)

好问题。问题是有很多解决方案,其中大部分都可以使用。

我与MVC合作很多,类似的情况经常发生。特别是在视图中,当需要在某些视图中进行类似渲染时......但实际上并不属于视图。

假设我们的儿童班ChildList延伸BaseList

在子类中添加属性uiHandler。重载渲染函数,假设为toString(),并将uiHandler与您的特定UI / Design事物一起使用。

我写了一些东西,它是在PHP中...但你应该能够得到一个想法。它使您可以自由选择对象的显示方式,并可灵活地为特定对象使用特定的UI。

看看下面的代码,它似乎很多但是int并没有那么糟糕。

  • BaseList - 您的基类
  • BaseListUIExtended - 使用UI的基类,将可选的UI类作为构造函数参数。在C#4中,您可以使用可选项,否则使用2个构造函数。
  • UIBase - UI类的界面......
  • UIChildSpecific - UI类
  • ChildList - 由于BaseListUIExtended可选构造函数参数,可以使用或不使用UI的子类。

定义界面

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

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

}

定义基类,子类

//**************************************************************
//  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    
}

...测试

//**************************************************************
//  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>