我正在开发一个系统,我希望自己的层尽可能地解耦,你知道,某种模块化的应用程序可以在不对系统其他部分进行认真修改的情况下切换数据库和其他东西。
所以,我一直在关注x--罗伯特·C·马丁(RobertC.Martin)关于良好实践、干净代码、解耦体系结构等的讨论之一,以获得一些灵感。我觉得有点奇怪的是他对系统Fitnesse的描述,以及他们为WikiPage实现存储/加载方法的方式。
他所描述的(至少根据我的理解)是,实体知道如何从某个持久层存储和加载自己的机制。当他想要在内存中存储WikiPages时,他只是简单地重写了WikiPage并创建了一个新的InMemoryWikiPage。当他想把它们存储在数据库里时,他做了同样的事情.
所以,我的一个问题是--这个方法叫什么?我一直在学习关于存储库模式之类的东西,为什么要像这样持之以恒--无知,但是我似乎找不到他做的事情的任何材料。因为我的应用程序将由模块组成,我认为这可能有助于解决我的问题,而不需要为我的实体创建一些集中存储。每个模块只需照顾自己,包括其实体的持久性。
我认为代码应该是这样的:
public class Person : IEntity
{
public int ID { get;set; }
public string Name { get;set; }
public void Save()
{
..
}
public void Update()
{
}
public void Delete()
{
}
...
}听起来有点奇怪但是..。或者我误解了他在视频里说的话?
我的第二个问题是,如果您不同意这种方法,,您将在这样的模块化应用程序中选择什么路径?
如果可能的话,请举例说明一下。
发布于 2013-04-12 11:12:34
您发布的模式是一个活动记录。
Repository和Active Record模式的区别在于,在活动记录模式、数据查询和持久化中,域对象位于一个类中,其中,与Repository一样,数据持久化和查询与域对象本身分离。
您可能想要查看的另一个模式是查询对象,它不同于respository模式,在每个可能的查询(筛选、排序、分组等)中,它的方法数量都会增加,查询对象可以使用fluent接口来表示[1],或者专门用于传递参数[2]。
最后,您可以查看命令查询责任分离体系结构以获得想法。我个人随心所欲,只是学到了一些对我有帮助的想法。
希望这能有所帮助。
根据评论更新
储存库模式的一个变化是
UserRepository
{
IEnumerable<User> GetAllUsers()
IEnumerable<User> GetAllByStatus(Status status)
User GetUserById(int id)
...
}这个不扩展,因为存储库被更新,以便以这种方式进行额外的查询
另一个变化是将查询对象作为参数传递给数据查询。
UserRepository
{
IEnumerable<User> GetAll(QueryObject)
User GetUserById(int id)
...
}
var query = new UserQueryObject(status: Status.Single)
var singleUsers = userRepo.GetAll(query)在.Net世界中,Linq表达式被传递,而不是QueryObject。
var singleUsers = userRepo.GetAll(user => user.Status == Status.Single)另一个不同的方法是将Repository专门用于通过其唯一标识符对一个实体进行检索并保存它,而query对象则用于提交数据检索,就像在CQRS中一样。
更新2
我建议你熟悉固体原理。这些原则非常有助于指导您创建一个松散耦合、高度内聚的体系结构。
洛斯特写的实价汇编包含关于实心原则的很好的介绍性文章。
发布于 2013-04-12 12:08:35
我将回答你的第二个问题。我想你也会对Dependency Injection感兴趣的。
我不是DI方面的专家,但我会尽我所能解释清楚。
首先,来自维基百科:
依赖注入是一种软件设计模式,它允许删除硬编码的依赖项,并使在运行时或编译时更改它们成为可能。 依赖注入模式的主要目的是允许在运行时中选择给定依赖接口的多个实现,或者通过配置文件,而不是在编译时。
有许多库可以帮助您实现这种设计模式: AutoFac、SimpleInjector、many、Spring.NET和许多其他库。
理论上,这就是您的代码的样子(AutoFac示例)
var containerBuilder = new ContainerBuilder();
//This is your container builder. It will be used to register interfaces
// with concrete implementations然后,注册接口类型的具体实现:
containerBuilder.RegisterType<MockDatabase>().As<IDatabase>().InstancePerDependency();
containerBuilder.RegisterType<Person>().As<IPerson>().InstancePerDependency();在本例中,InstancePerDependency意味着每当您尝试解析IPerson时,都会得到一个新实例。例如,它可能是SingleInstance,所以每当您试图解析IPerson时,您都会得到相同的共享实例。
然后构建容器,并使用它:
var container = containerBuilder.Build();
IPerson myPerson = container.Resolve<IPerson>(); //This will retrieve the object based on whatever implementation you registered for IPerson
myPerson.Id = 1;
myPerson.Save(); //Save your changes我在本例中使用的模型:
interface IEntity
{
int Id { get; set; }
string TableName { get; }
//etc
}
interface IPerson: IEntity
{
void Save();
}
interface IDatabase
{
void Save(IEntity entity);
}
class SQLDatabase : IDatabase
{
public void Save(IEntity entity)
{
//Your sql execution (very simplified)
//yada yada INSERT INTO entity.TableName VALUES (entity.Id)
//If you use EntityFramework it will be even easier
}
}
class MockDatabase : IDatabase
{
public void Save(IEntity entity)
{
return;
}
}
class Person : IPerson
{
IDatabase _database;
public Person(IDatabase database)
{
this._database = database;
}
public void Save()
{
_database.Save(this);
}
public int Id
{
get;
set;
}
public string TableName
{
get { return "Person"; }
}
}别担心,AutoFac会自动解决任何Person依赖项,比如IDatabase。
这样,如果您想要切换数据库,只需这样做:
containerBuilder.RegisterType<SqlDatabase>().As<IDatabase>().InstancePerDependency();我编写了一个过于简化(不适合使用)的代码,它只是作为一个启动,谷歌“依赖注入”的进一步信息。我希望这能帮到你。祝你好运,
https://stackoverflow.com/questions/15969293
复制相似问题