假设我有一个域对象的类层次结构,其中包含一个基类和几个子类,一个级别。
假设我有一个这些对象的列表(基类列表),我想将一些逻辑应用于我认为不属于类的类(例如,设计/ UI特定代码)。
我的替代方案是什么?
If-is statement。就个人而言,这个甚至不应该被视为一种替代方案,但无论如何我都要写它。
多态性。在某些情况下,这个实际上是另一种选择,但在上面的示例中,我不希望我的类包含任何UI细节。
根据对象的类型,通过反射/ IoC容器解析一些逻辑方法
例如C#。类型type = typeof(ILogic<>)。MakeGenericType(domainObject.GetType());
我真的很喜欢这个,我没有得到任何编译时间检查,但是如果子类缺少一个实现,或者这可能是某种方式?
访客模式。会起作用,但是在一个只有一层深的结构上应用有点矫枉过正。
任何人都有其他任何提示或技巧来解决这些问题吗?
答案 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>