作为输入,我有一个书籍列表。作为输出,我期待一个SimilarBookCollection。
SimilarBookCollection有一个author,publishYear和Books列表。如果书籍的作者不同或者publishYear不同,则无法创建SimilarBookCollection。
目前在PHP中的解决方案:
client.php
----
$arrBook = array(...); // array of books
$objValidator = new SimilarBookCollectionValidator($arrBook);
if ($objValidator->IsValid()) {
$objSimilarBookCollection = new SimilarBookCollection($arrBook);
echo $objSimilarBookCollection->GetAuthor();
}
else {
echo 'Invalid input';
}
SimilarBookCollection.php
---
class SimilarBookCollection() {
public function SimilarBookCollection(array $arrBook) {
$objValidator = new SimilarBookCollectionValidator($arrBook);
if ($objValidator->IsValid()) {
throw new Exception('Invalid books to create collection');
}
$this->author = $arrBook[0]->GetAuthor();
$this->publishYear = $arrBook[0]->GetPublishYear();
$this->books = $arrBook;
}
public function GetAuthor() {
return $this->author;
}
public function GetPublishYear() {
return $this->publishYear;
}
public function GetBooks() {
return $this->books;
}
}
SimilarBookCollectionValidator.php
---
class SimilarBookCollectionValidator() {
public function IsValid() {
$this->ValidateAtLeastOneBook();
$this->ValidateSameAuthor();
$this->ValidateSameYear();
return $this->blnValid;
}
... //actual validation routines
}
目标是拥有一个“特殊”集合,其中只有具有相同作者和publishYear的书籍。我们的想法是从对象轻松访问作者或年份等重复信息。
您如何命名SimilarBookCollection?目前的名字是 通用的。使用像SameYearAuthorBookCollection这样的名称看起来有点像 很长很奇怪(如果添加更多条件,那么名字会增加)
你会在SimilarBookCollection构造函数中使用一个Validator吗? 防御性编程风格?
您是否会更改代码的设计?如果是,如何?
答案 0 :(得分:0)
一切都取决于;)
因此,如果我的目标是通用适应性解决方案,我会执行以下操作:
构造函数中的Validator 一方面你要验证两次;如果前提条件/合同损坏(没有给出有效的清单),那就是提供信息,但运行的代码是两倍 - 究竟是出于什么目的? 如果你想在系统中使用它,取决于它的大小,它的重要性,产品阶段,以及可能更多的标准。 但是它也是控制器逻辑适合模型,这意味着你正在传播你的代码。
我不会把它放在构造函数中。
名称/设计 我会说BookCollection一直保持通用,并且在控制器空间中严格进行任何验证,而不是膨胀集合,这实际上似乎是一个带有额外字段的作者的数组。
如果要区分不同的集合类型,请使用(多个)继承或某种附加字段“collectionType”;前者,如果你期望许多衍生物或不同的功能来(也保持逻辑在不同的地方很好地分开)。
您还可以将您的集合视为一个执行查询的集合,为方便起见,您可以维护某些元数据,如$ AuthorCount = N,$ publicationDates = array(...),您可以从中快速派生集合的本质。这种方法还可以使验证器代码保持最小(或不存在),因为它隐含在集合中,您可以在控制器中进行验证,使其背后的有效逻辑清晰可见。
这也将使你今后感觉更舒服。但问题确实是你想要的,需要它,以及你期望的变化,因为你应该根据你的要求和可能的变化来适应你的设计。
对于非常特殊的问题,我理解的约束如下:
如果不是第1点,我将使用参数化的通用基类(即,在实例化时告诉它是相同属性的集合)或使用多重继承(或在php特征中)与组合构成任意组合。需要的接口。子项可能依赖于基类,但使用相同属性的预定义子集。
参数化变体可能如下所示:
class BookCollection {
public function __construct($book_list, $identical_fields=array())
{
if (empty($book_list))
{
throw new EmptyCollectionException("Empty book list");
}
$default = $book_list[0];
$this->ia = array();
foreach($identical_fields as $f)
{
$this->ia[$f] = $default->$f;
}
foreach($book_list as $book)
{
foreach($identical_fields as $f)
{
if ($this->ia[$f] !== $book->$f)
{
throw new NotIdenticalFieldException("Field $f is not identical for all");
}
}
}
$this->book_list = $book_list;
}
public function getIdentical($key)
{
$this->ia[$key];
}
}
final class BC_by_Author extends BookCollection{
public function __construct($book_list)
{
parent::__construct($book_list,array('author'));
}
public function getAuthor(){ $this->ia['author']; }
}
或者抽象和最终类型(不确定它是否有效)
abstract class BookCollection{
public final function __construct($book_list){...}
abstract public function getIdenticalAttributes();
}
final class BC_by_Author {
public function getIdenticalAttributes(){ return array('author'); }
public function getAuthor(){ return $this->ia['author']; }
}
如果依赖于不一定与字段名称匹配的getter,我会选择多重继承/特征。 然后命名就像BC_Field1Field2Field3。
或者或另外,您也可以使用完全相同的类名,但在不同的命名空间中开发您的解决方案,这意味着您在更改命名空间时不必更改代码,而且可以在控制器中保持简短
但是因为只会有一个类,我会把它命名为BookCollection而不必再进一步讨论它。
由于约束4,白盒约束,给定的书列表必须由类本身验证,即在构造函数中验证。