功能羡慕,封装,活动记录,关注点分离?什么时候是坏的?



你们都说,面向对象编程是关于封装、数据隐藏的。让我们给出这个例子:

class Rectangle
{
private int a,b;
public function __construct(int a, int b)
{
this.a = a;
this.b = b;
}
int public function getA()
{
return a;
}
int public function getB()
{
return b;
}
}
var r = new Rectangle(3, 4);
var area = r.getA() * r.getB();

这是一个不好的代码,所以让我们重新构造:

class Rectangle
{
private int a,b;
public function __construct(int a, int b)
{
this.a = a;
this.b = b;
}
int public function getArea()
{
return a*b;
}
}
r = new Rectangle(3, 4);
area = r.getArea();

更好,数据隐藏完成,getArea被带到它所属的位置。好的,下面是活动记录:

class Record
{
private int ID;
private string username;
public function __constructor(int ID, string username)
{
this.ID = ID;
this.username = username;
}
int public function getID()
{
return ID;
}
string public function getUsername()
{
return username;
}
}
r = new Record(1, 'test');
dbEngine.save(r);

这也是不好的,因为所有数据都是公开的。(尽管学说是这样工作的)但是如果我像Propel那样做:

class Record
{
private int ID;
private string username;
public function __constructor(int ID, string username)
{
this.ID = ID;
this.username = username;
}
public function save()
{
dbEngine.save([ID, username]);
}
}
r = new Record(1, 'test');
r.save();

也被称为bad,因为活动记录是反模式的。那是好是坏呢?什么时候"行动"?(getArea, save)应该被带到一个对象内部-它什么时候在外部起作用?

您可以针对您的具体情况注入dbEngine依赖项,但这并不能解决您的问题。

一般来说,让你的代码好起来的是它有多容易理解,以及意图的变化与实现的变化有多紧密。

揭示私有内部的问题是,你暴露了与你的程序接口的程序可能依赖的内部值(并且使以后难以更改)。记录基本上是一个结构体/数据类——它代表了一组值,这些值与一些定义良好的含义一起出现。在不知道其余代码的情况下,我不能说这个特定的类是否像这样,但如果是这种情况,则可以将其设置为结构体(所有成员都是public,没有方法)。

没有什么包罗万象的规则能让代码"好"。这是一个不断犯错或效率低下的过程,并分析是什么代码导致或导致了更有可能出现的问题。代码气味只是其他人大量试验和错误的结果,尽管在大多数情况下非常健壮,但有时可能过时,应该在改进代码的特定情况下应用。

你的例子都不错。它们只是设计选择。在第二个例子中删除a和b的访问器对我来说似乎是一种倒退。至于在类定义中放置依赖于实现的保存代码,如果有多个类型都需要定义保存,那就不好了。在这种情况下,最好使用save函数定义父类,然后从该类继承。然而,如果你只是在写代码,而且只有一个类,那就没关系了。

很好,你在思考什么是好的代码。作为一般规则,好的代码是可以工作的代码,你可以在6个月后返回,并且在将来很容易修改。如果你有一组开发人员,那么当然要提供访问器。

好的代码的另一个方面是有单元测试。如果您更改了某些内容并且单元测试通过了,那么您就完成了您的工作。如果有人正在使用内部代码,他们应该编写一个单元测试,以通知可能破坏他们代码的更改。

最新更新