我正在从头开始编写一个新的网站项目。该项目是 C#,但我的背景是 PHP(下面的伪代码有点混合,试图既简洁又具有声明性)。
问题
我需要从两个地方之一检索配置数据——有时来自本地数据库,有时来自 Soap 服务。我应该能够从任一源创建相同的模型对象集。
数据以完全不同的结构存储在不同的数据源中——几个不同的 Soap 响应需要从 Soap 端拼凑在一起,而 DB 结构更接近于我在代码中构建模型对象的方式。
配置由对象树组成:产品包含属性,其中包含选项,这些选项在应用时具有条件。
目标
我想尽可能地分离关注点(希望有利于测试/维护/扩展能力):
- 我的模型对象应该对数据持久性或检索一无所知
- Data Persistence 对象应尽可能与数据源的确切类型无关
- 我想尽可能地将对象创建分开。
问题
我知道围绕这一点的各种设计模式(尽管我不完全确定我完全理解它们)。我在 Programmers 上问了一个与此类似的问题,并得到了关于Persistence Ignorance(更多此处)和Repository模式的回复,这两个似乎都是来自 Microsoft 世界的概念。
据我所知,“持久性无知”只是让模型对象对您的数据存储机制一无所知的概念,并且存储库模式似乎与数据映射器模式非常相似,除了它可能更像是一个门面,隐藏更多实际发生的事情。
所以我的问题是:
在数据映射器模式中,每个模型对象应该有一个映射器吗?而不是为整个配置树设置一个?
因此,我是否应该有一个使用所有这些 Mapper 对象的配置树构建对象?
class ConfigBuilder() {
public ConfigBuilder (productMapper, propertyMapper, optionMapper, conditionMapper) {
// save them into local properties
}
public Products() {
var products = productMapper.FetchAll();
foreach (var product in products) {
AddProperties(product);
}
return products;
}
private AddProperties(products) { /* ... */ }
private AddOptions(property) { /* ... */ }
private AddConditions(option) { /* ... */ }
}
这似乎是一个很好的解决方案?
构建对象的逻辑应该放在哪里?
在某些时候,需要大量的逻辑来从我从 Soap 服务返回的 XML 数据的随机数组构建我的配置对象,并且需要少量的逻辑来从数据库中做同样的事情。
我应该将构建对象的逻辑放在 Mapper 对象的单独实例中吗?
interface IProductMapper { FetchAll; FetchByCode; Create; Delete; Update }
class ProductMapperXml implements IProductMapper {
public ProductMapperXml(xmlDataSource) {}
public FetchAll() { /* A whole bunch of logic to create the Product objects from XML data source */ }
}
class ProductMapperDatabase implements IProductMapper {
public ProductMapperDatabase(databaseConnection) {}
public FetchAll() { /* Select and build products from the database */ }
}
这个可以吗?是否应该进一步抽象这个逻辑?如果是,为什么?另外,我对ProductMapperXml
对象本身具有相当大的逻辑并且还负责在Product
内部创建对象感到有些不安。我应该以ProductFactory
某种方式传递它吗?还是只使用工厂方法?
请让我知道是否有比我的建议更优雅的方法来解决这个问题?此外,如果我错过了任何抽象层或设计模式,我可以从中受益吗?