Rob*_*low 5 c# model-view-controller design-patterns data-access-layer datamapper
我正在从头开始编写一个新的网站项目.该项目在C#中,但我的背景是在PHP中(下面的伪代码有点混合,试图简洁和声明).
问题
我需要从两个地方之一检索配置数据 - 有时从本地数据库,有时从Soap服务.我应该能够从任一源创建同一组Model对象.
数据存储在不同数据源中完全不同的结构中 - 需要从Soap端拼凑出几个不同的Soap响应,而DB结构更接近于我在代码中构建模型对象的方式.
配置由对象树组成:产品包含属性,其中包含选项,这些选项具有应用时间的条件.
目标
我想尽可能地分开关注点(希望能够促进测试/维护/扩展能力):
问题
我知道各种各样的设计模式(虽然我不完全确定我完全理解它们).我向程序员提出了一个与此类似的问题,得到了关于Persistence Ignorance(更多信息)和Repository模式的回复,它们似乎都是来自Microsoft世界的概念.
据我所知,"Persistence Ignorance"只是让Model对象对你的数据存储机制一无所知的概念,而Repository模式看起来与Data Mapper模式非常相似,只不过它可能更像是一个外观,隐藏更多实际发生的事情.
所以我的问题是:
在Data Mapper模式中,每个Model对象应该有一个Mapper吗?而不是一个整个配置树?
因此,我应该有一个使用所有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) { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
这似乎是一个很好的解决方案吗?
构建对象的逻辑应该放在哪里?
在某些时候,需要有大量的逻辑来从我从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 */ }
}
Run Code Online (Sandbox Code Playgroud)
这个可以吗?这个逻辑应该进一步抽象吗?如果是这样的话?此外,我对这个ProductMapperXml具有相当逻辑的对象有点不安,并且还负责在Product内部创建对象.我应该通过ProductFactory某种方式吗?或者只是使用工厂方法?
如果有比我的建议更优雅的方法来解决这个问题,请告诉我们?此外,如果有任何抽象层或设计模式,我可以从我错过的中获益吗?
由于没有答案,我将自己写下来。
我最终确实采用了这种DataMapper模式——我希望我以一种明智的方式实现它。
我最终没有使用任何工厂类,因为我能够通过类本身构建树。
我创建了一堆Mapper接口:
interface Models.Interfaces.IModel {}
interface Mappers.Interfaces.IMapper {}
interface Mappers.Interfaces.IDatabaseMapper : IMapper {}
interface Mappers.Interfaces.IXmlMapper : IMapper {}
Run Code Online (Sandbox Code Playgroud)
我为一切创建了模型:
class Models.Product : IModel {}
class Models.Property : IModel {}
class Models.Option : IModel {}
class Models.Condition : IModel {}
Run Code Online (Sandbox Code Playgroud)
然后我给每个模型两个映射器类:
class Mappers.ProductDatabaseMapper : IDatabaseMapper {}
class Mappers.ProductXmlMapper : IXmlMapper {}
/* ... (same for each model) */
Run Code Online (Sandbox Code Playgroud)
每个 Mapper 类都有创建其子级的方法:
class ProductDatabaseMapper :IDatabaseMapper {
public List<Product> FetchAllWithChildren {
var productRows = DbManager.FetchAll("Product");
var products = List<Product>();
foreach(var productRow in productRows) {
var product = new Product(productRow["Name"]);
product.Properties = PropertyManagerInstance.FetchAllWithChildren(product);
products.Add(product):
}
return products;
}
}
Run Code Online (Sandbox Code Playgroud)
我认为这提供了一个相当巧妙的解决方案。尽管我仍然有点担心我的各个Mapper类正在自己创建对象这一事实。但我认为只有在必要时我才会将其分离到工厂中。
| 归档时间: |
|
| 查看次数: |
2885 次 |
| 最近记录: |