回答迟了,但我无法抗拒。
X是进入Y的最多类还是反模式?
在大多数情况下,大多数规则,如果不加考虑,就会大为改错(包括这一规则)。
让我告诉你一个关于一个对象的诞生的故事,该对象是在一些正确的,快速而又肮脏的程序代码的混乱中发生的,这不是设计使然,而是出于绝望。
我和我的实习生结对编程,可以快速创建一些可丢弃的代码来抓取网页。我们绝对没有理由期望此代码可以使用很长时间,所以我们只是敲出一些可行的方法。我们以字符串的形式抓取整个页面,并以您能想象到的最脆弱的方式切碎我们所需的内容。不要判断 有用。
现在,在执行此操作的同时,我创建了一些静态方法来进行斩波。我的实习生创建了一个非常像您的DTO课程CatData
。
当我第一次查看DTO时,它困扰了我。多年来,Java对我的大脑造成的伤害使我在公共领域退缩了。但是我们正在使用C#。C#不需要过早的getter和setter来保留使数据不可变或稍后封装的权利。在不更改界面的情况下,您可以随时添加它们。也许只是这样,您可以设置一个断点。所有这些都没有告诉您的客户有关此事的事情。是的C#。Boo Java。
所以我握住了舌头。我看着他在使用之前用我的静态方法初始化了这个东西。我们大约有14个。丑陋,但是我们没有理由在意。
然后我们在其他地方需要它。我们发现自己想要复制并粘贴代码。14行初始化。它开始变得痛苦。他犹豫了一下,问我要点什么。
我无奈地问,“你会考虑一个物体吗?”
他回头看了看DTO,困惑地拧紧了脸。“这是一个对象”。
“我的意思是真实的对象”
“ Hu?”
“让我给你看一些东西。你决定是否有用”
我选择了一个新名称,然后迅速整理出一个看起来像这样的东西:
public class Cat{
CatData(string catPage) {
this.catPage = catPage
}
private readonly string catPage;
public string name() { return chop("name prefix", "name suffix"); }
public string weight() { return chop("weight prefix", "weight suffix"); }
public string image() { return chop("image prefix", "image suffix"); }
private string chop(string prefix, string suffix) {
int start = catPage.indexOf(prefix) + prefix.Length;
int end = catPage.indexOf(suffix);
int length = end - start;
return catPage.Substring(start, length);
}
}
静态方法还没有做任何事情。但是现在,我将14种静态方法吸收到了一个类中,在这些类中它们可以与所处理的数据一起使用。
我没有强迫实习生使用它。我只是提供了它,让他决定他是否要坚持使用静态方法。我回到家里,以为他可能会坚持他已经从事的工作。第二天,我发现他在很多地方使用它。它使其余的代码变得杂乱无章,这些代码仍然很丑陋,而且程序繁琐,但是现在我们在一个对象后面隐藏了这一点复杂性。好一点了。
现在确定每次访问此功能都会做很多工作。DTO是一个很好的快速缓存值。我对此感到担心,但是意识到我可以在需要时添加缓存,而无需接触任何使用代码。因此,在我们关心之前,我不会打扰。
我是说您应该始终在DTO上坚持OO对象吗?不。当您需要越过边界使您无法移动方法时,DTO会大放异彩。DTO占有一席之地。
但是OO对象也是如此。了解如何使用这两种工具。了解每笔费用。学会让问题,情况和实习生决定。Dogma不是您的朋友。
由于我的回答已经很荒谬了,所以让我在审查您的代码时避免一些误解。
例如,一个类通常具有类成员和方法,例如:
public class Cat{
private String name;
private int weight;
private Image image;
public void printInfo(){
System.out.println("Name:"+this.name+",weight:"+this.weight);
}
public void draw(){
//some draw code which uses this.image
}
}
您的构造函数在哪里?这还不足以让我知道它是否有用。
但是在阅读了有关“单一职责原则”和“开放封闭原则”之后,我更喜欢仅使用静态方法将类分为DTO和辅助类,例如:
public class CatData{
public String name;
public int weight;
public Image image;
}
public class CatMethods{
public static void printInfo(Cat cat){
System.out.println("Name:"+cat.name+",weight:"+cat.weight);
}
public static void draw(Cat cat){
//some draw code which uses cat.image
}
}
我认为这符合单一职责原则,因为现在CatData的职责是仅保留数据,而不关心方法(对于CatMethods也是如此)。
您可以以“单一责任原则”的名义做很多愚蠢的事情。我可以争辩说Cat Strings和Cat int应该分开。该绘图方法和图像必须都具有自己的类。您正在运行的程序是一项责任,因此您应该只有一个班级。:P
对我而言,遵循“单一责任原则”的最好方法是找到一个好的抽象,让您将复杂性放在一个盒子中以便将其隐藏。如果您能给它起一个好名字,可以使人们对他们进入内部时所发现的东西不感到惊讶,那么您对它的了解就很好。期望它决定更多的决定,然后就会带来麻烦。老实说,您的两个代码清单都这样做,所以我看不到SRP在这里为什么重要。
而且它也符合开放式封闭原则,因为添加新方法不需要更改CatData类。
好吧 打开关闭原理与添加新方法无关。它是关于能够更改旧方法的实现,而无需进行任何编辑。什么都不会使用您,不会使用您的旧方法。相反,您在其他地方编写了一些新代码。某种形式的多态可以很好地做到这一点。在这里看不到。
我的问题是,这是好的还是反模式的?
好吧,我怎么知道?看,以任何一种方式进行都具有收益和成本。当您将代码与数据分开时,您可以更改其中一个而不必重新编译另一个代码。也许这对您至关重要。也许这只会使您的代码变得毫无意义。
如果这样会让你感觉更好,马丁•福勒(Martin Fowler)称之为参数对象的地方就差不多了。您不必仅将基元带入对象。
我希望您做的是对两种编码方式之间的分离有所了解。因为信不信由你,您不会被迫选择一种样式。您只需要选择就可以生活。