在将大型类重构为较小的类之前,您是否查看了方法使用的变量? [关闭]
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在将大型类重构为较小的类之前,您是否查看了方法使用的变量? [关闭]相关的知识,希望对你有一定的参考价值。
我有兴趣探索这样一种观点,即方法与他们使用的成员varialbes之间的关系可以暗示如何将类分解为更小的部分。这个想法是一组变量与一个责任密切相关,并且应该根据SRP包含在一个类中。
对于一个简单的例子,一个类如:
public class Rectangle {
private int width;
private int height;
private int red,green,blue;
public int area() { return width * height; }
//just an example, didn't check the api.
public Color color () { return new Color (red, green, blue); }
}
应该重构为:
public class Rectangle {
private Dimension size;
private Color color;
...
}
因为分解将是:
面积:宽度,高度颜色:红色,绿色,蓝色
由于这些变量在相同的方法中使用,因此它们明显相关,并且可以制成它自己的类。我知道这个例子可能太琐碎了,但请耐心等待,并尝试在这里思考更大。如果其他方法也使用这些变量,则它们很可能也相关,也可以移动到新类中。
只是为了好玩,我创建了一个尝试这样做的小plugin for Eclipse。它将对方法 - >变量,变量 - >方法进行细分,并尝试将方法组合在一起,然后直接或间接使用这些变量。
这是你在编码时做的事情,它实际上有用吗?
我不能说这曾经是我在编码时想到的东西。是的,它可能会带来一些改进,但我认为你在实践中发现自己要做的就是创建大量的类,这些类更难以处理。
不过,作为“代码味道”,它可能有一些优点。如果你看到一个包含大量成员变量的类,并且大多数只使用少数方法,那通常是一个不好的标志。
我可以想象这是一种合理的代码味道。在我们的例子中,简单的setter / getter并不太有说服力。例如,重构只会产生一个带有a和b的更复杂的对象:
public class A {
private String a1;
public void aMeth () {
print(a1);
}
}
public class B {
private String b1;
public void bMeth () {
print(b1);
}
}
public class A {
private A a;
private B b;
... insert infinite regress
}
但是,我可以看到这是一个指南,你有一组变量纠缠在大怪物类中,其中变量分组对应于概念分解。你在想更多这样的事吗?
public class Rectangle {
private int width;
private int height;
private int red,green,blue;
public int area() { return width * height; }
//just an example, didn't check the api.
public Color color () { return new Color (red, green, blue); }
}
矩形应具有尺寸和颜色。在我看来,如果你能清楚地发现只有彼此纠缠的私有变量集,这是一个有用的东西,只要你省略非纠缠变量(即如果你把变量看作图顶点,我想你想要检测连接的子图但省略大小为1的子图
我认为每个类应该按照它的作用来组织,而不是它将使用什么变量。我建议让每个班级都有一个目的(单一责任原则)。而不是根据他们对变量的使用来分解,根据他们的责任或目的来分离类。
在我看来,编写干净的代码不仅仅是代码看起来有多好,而且还有多容易阅读。代码应按逻辑分组并具有一致的样式。请记住,某些类不会使用所有变量。在java中你有mutator和accessor方法。这些方法用于获取或设置单个变量。
例:
public class Rectangle {
private int lenght = 0;
private int width = 0;
public Rectangle (int length, width)
{
this.length = length;
this.width = width;
}
public int getLength(int length)
{
return length;
}
public int getWidth(int width)
{
return wdith;
}
public void setLength(int length)
{
this.length = length;
}
public void setWidth(int width)
{
this.width = width;
}
}
我不会将此类拆分为RectangleLength和RectangleWidth类。这些方法只承担单一责任,即表示矩形。如果此类包含数学函数,您可能希望将其分解为RectangleGeometry类。
我做到了这一点。甚至创建了一个表,第一列中的方法,顶部的实例变量,以及指示哪个使用哪个。然后排序 - 有点像热图这样排序,但更随意,更手动 - 看看哪些变量,以及哪些方法一起跟踪。它有效并且很有用。但它深深扎根于我的诡计之中;我很少使用它。我必须看看你的插件;如果这样做的工作较少,我可能会做得更多。
这当然是一种很好的重构方法。在Working Effectively With Legacy Code中,Michael Feathers在一个名为Seeing Responsibilities的部分中描述了一种技术:
启发式#4寻找内部关系
寻找实例变量和方法之间的关系。某些方法使用某些实例变量而不是其他方法吗?
然后,他继续描述一种方法,您可以在其中绘制一个称为特征草图的图表,该图表显示了类和内部方法调用的方法。从图中,您可以轻松地直观地识别互连方法调用的集群,这些调用是重构为新的,更具凝聚力的类的候选者。
如果您的Eclipse插件可以快速生成图书中描述的图形,那将是非常酷的 - 我可以看到它是一个有用的重构工具。
听起来像有人读到有关Law of Demeter的内容,并试图将其置于极端。我不得不说,我总是以一定的谨慎态度对待“脱钩”狂热者,尤其是因为有些人确实提倡设计中的“零耦合”,而忽略了这样一个事实,即没有任何耦合,系统就没用了。
尽管如此,减少代码中的依赖性使得测试更容易,并且对其他重构更具弹性,而且我发现它往往会导致更简单,更明显的代码。健康的平衡是努力的目标。
总体而言,这似乎是一个坏主意。
首先,类表示相关数据和/或方法的集合。它根本不需要任何方法来保持有用的类。为了获得良好的封装,您可能需要吸气剂和固定剂;根据定义,这些方法不会访问多个变量。这并不意味着这些变量是否属于同一个类。
最后,一个方法属于该类,如果它提供了一种操作类,计算自身的一些信息,构造类等的方法;方法可能属于某个类但不能访问大多数成员变量的原因有很多。然后是静态方法;根据定义,这些应该在其他类别吗?
如果一个类中包含太多概念,则应该将其拆分。但这些概念只是松散地映射到方法和变量。计算变量使用是一种可靠的方法,可以使您的类层次结构过于复杂,而且没有任何好处。
以上是关于在将大型类重构为较小的类之前,您是否查看了方法使用的变量? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章