Разработка вариантов удаления операторов if-is - PullRequest
3 голосов
/ 28 сентября 2010

Допустим, у меня есть иерархия классов объектов домена с одним базовым классом и несколькими дочерними классами одного уровня.

Допустим, у меня есть список этих объектов (список базового класса), и я хочу применить некоторую логику к классам, которые, на мой взгляд, на самом деле не относятся к классам (например, код, специфичный для дизайна / пользовательского интерфейса).

Какие у меня есть альтернативы?

  1. If-is утверждение. Лично это не следует даже рассматривать как альтернативу, но я все равно пишу.

  2. полиморфизм. В некоторых случаях этот вариант фактически является альтернативой, но в моем примере выше я не хочу, чтобы мои классы содержали какие-либо особенности пользовательского интерфейса.

  3. Разрешение некоторого логического метода с помощью контейнера отражения / IoC в зависимости от типа объекта.
    Например, C #. Тип type = typeof (ILogic <>). MakeGenericType (domainObject.GetType ());
    Мне действительно нравится этот, я не получаю никаких проверок времени компиляции, хотя, если реализация отсутствует для подкласса, или это как-то возможно?

  4. Шаблон посетителя. Будет работать, но кажется, что это излишнее применение для структуры, которая имеет только один уровень глубины.

У кого-нибудь есть какие-либо другие советы или хитрости для решения подобных проблем?

1 Ответ

2 голосов
/ 30 сентября 2010

Отличный вопрос. Проблема в том, что существует много решений, и большинство из них будут работать.

Я много работаю с MVC, подобная ситуация случается довольно часто. Особенно в представлении, когда подобный рендеринг должен происходить в некоторых представлениях ... но на самом деле он не принадлежит представлению.

Допустим, у нас есть дочерний класс ChildList, который расширяет BaseList.

Добавьте свойство uiHandler в дочерний класс. Перегрузите функцию рендеринга, скажем, toString(), и используйте uiHandler со своими специфическими элементами пользовательского интерфейса / дизайна.

Я кое-что написал, это на PHP ... но у вас должна получиться идея. Это дает вам свободу выбора способа отображения ваших объектов и гибкость в использовании определенных интерфейсов для определенных объектов.

Посмотрите на приведенный ниже код, он выглядит много, но int не так уж и плох.

  • BaseList - ваш базовый класс
  • BaseListUIExtended - базовый класс, который использует пользовательский интерфейс, принимает необязательный класс пользовательского интерфейса в качестве параметра конструктора. В C # 4 вы можете использовать необязательные, в противном случае используйте 2 конструктора.
  • UIBase - интерфейс для классов пользовательского интерфейса ...
  • UIChildSpecific - UI класс
  • ChildList - дочерний класс, который может использовать пользовательский интерфейс или нет, поскольку BaseListUIExtended необязательный параметр конструктора.

Определить интерфейс

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