我想提出一个我想出的设计模式。我没有看到它之前使用它是令人惊讶的,因为它修复了一个常见的问题,所以我想知道我是否还没有找到它,或者我的解决方案是不受欢迎的还是打破了任何主要的设计原则。如果有人可以向我提供任何描述,或提供意见或批评的链接。如果你没有,那么随意使用=)
我经常使用Active Record Pattern,因为它很简单,完全了解它在数据库上创建的不良耦合,以及使用丑陋的SQL代码来填充域对象。所以我的主张如下:
interface IUser{
getFirstName();
getLastName():
setFirstName();
setLastName();
}
class User implements IUser{
id:string;
firstName:string;
lastName:string;
constructor(id:string, firstName:string, lastName:string){
this.id=id;
this.setFirstName(firstName);
this.setLastName(lastName);
}
function getFirstName(){
return this.firstName;
}
function getLastName(){
return this.lastName;
}
function setFirstName(firstName:string){
this.firstName=firstName;
}
function setLastName(lastName:string){
this.lastName=lastName;
}
}
class UserDB implements IUser{
user:IUser;
constructror(user:IUser){
this.user=user;
}
function getFirstName(){
return this.user.getFirstName();
}
function getLastName(){
return this.user.getLastName();
}
function setFirstName(firstName:string){
this.this.setFirstName(firstName);
this.update();
}
function setLastName(lastName:string){
this.setLastName(lastName);
this.update();
}
function update(){
// sql execution script
// update user set first_name=getFirstName(), last_name=getLastName() where id=this.user
}
}
然后在代码中创建实例,无论是工厂还是用户的回购都会这样做:
function getUser(id:string):User{
// select first_name, last_name from user where id=id;
var user=new User(id, firstName, lastName);
var userdb=new UserDB(user);
return user
}
这可能是一个不好的例子,因为通常用户不会更改他们的名字或姓氏,但这是我能提出的最简单的例子!
我基本上使用GoF Decorator模式,但从未见过用这种方式进行数据访问。
对于每个属性更新执行db访问仍然会产生不良影响,就像活动记录模式一样,但它至少不会删除从User类到数据库的耦合并删除丑陋的SQL代码。 UserDB实现可以与其他数据访问类位于同一个包中。解决方案 unbreak 来自Active Record Pattern的SRP原则。我知道Active Record Pattern被一些人认为是一种反模式,但它很容易在简单的应用程序上使用,所以重点如下,如果你打算使用它,这不是一个更好的实现对吗?
编辑以回应Matia的评论:
Matias,非常感谢你的评论,批评正是我所寻求的。但是,我不同意你的结论,让我解释一下原因:
首先看一下你的示例User类,它是一个域实体,但却有数据存储的含义。域对象不应该有save()方法。我的示例(User类)确实是一个域对象。域对象不应该具有存储库的依赖性,尤其是在构造函数中(!)存储库关注数据存储问题,因此您立即向全世界声明用户域对象关注持久性。此外,User实例不应该知道如何保持自身或如何检索其他User实例 - 所以这是另一个重大违规。
虽然我知道人们确实从域对象引用存储库,但这被认为是非常糟糕的做法,并且在互联网上有很多引用这一点,为方便起见,这里有几个链接:
Is it ok for entities to access repositories?
http://thinkbeforecoding.com/post/2013/03/03/Entities-and-Repository-injection-ndash%3B-follow-up
如果您仍然认为用户类可以引用用户存储库,请查看这些链接,或者请与我分享任何得出相反结论的链接。
“单一责任原则。您的活跃记录拥有 持久性逻辑。“
你是绝对正确的,UserDB拥有持久性逻辑,但这正是Active Record Pattern应该做的,并且记住我正在将我的解决方案与那个解决方案进行比较。
但我所做的和我的提议的重点是将持久性逻辑依赖性与域层分离,从而从中删除SQL,因为UserDB将驻留在数据访问层中,允许我的User类真正属于在域层中,而您的用户类却不能。
“依赖倒置原则。你创建依赖关系 实现而不是抽象。“
关于依赖于具体类,我假设你引用的是我正在从具体的User类扩展UserDB类这一事实?我知道具体的依赖性,但是通过引入IUser接口并让User和UserDB都实现它可以很容易地消除它,但是我试图保持代码最小化以达到预防和方便的目的。所以我确实认识并同意这一点,但它很容易纠正。
“正如你可以检查我的样本,我不是坚持活跃的记录 设置属性时更改,但是当User.Save()为时,它会完成 叫,这似乎是一种更好的方法。“
如果性能是一个问题,那么我会考虑不在每个属性更新上调用它,但它会再次存在于UserDB而不是像您的样本那样的User类,原因我认为我已经解释过了。
答案 0 :(得分:0)
完全了解它在数据库上创建的不良耦合, 并且使用丑陋的SQL代码来破坏域对象
实际上这个陈述可能是错误的,因为整个活动记录可以注入一个从头开始解决问题的存储库。
在C#中:
public class User
{
public User(IUserRepository repository)
{
Repository = repository;
}
private IUserRepository Repository { get; }
public string Name { get; set; }
public string LastName { get; set; }
public void Save()
{
Repository.Update(this);
}
}
正如您可以查看我的示例,我不会在设置属性时保持活动记录的更改,但是在{{1被调用,这似乎是一种更好的方法。
您是否想指出哪些原则会违反您的方法?至少我发现了两个: