我倾向于创建具有30-40(或更多)方法的非常大的类。有多少方法太多了?是否有任何“气味”或经验法则可供使用?
答案 0 :(得分:45)
第一步是坚持Single Responsibility Principle。如果你不能用一句话说出你班级的作用,那么它可能会做得太多。
一旦你缩小了范围,我不知道只要你的方法don't do too much,方法的数量真的很重要。
答案 1 :(得分:23)
静态属性非常值得怀疑。强烈质疑他们是否真的需要。
类的大多数属性/属性应该是私有的(只能由对象实例访问)或受保护,只能由类或派生类(子类)的实例访问。
如果某个类的属性/属性对普通公众可见,则它很可能是只读的。在大多数情况下,对象实例的状态应该仅通过响应一个方法来改变,要求它做一些有用的事情(例如,你请求一个窗口自己移动,而不是显式设置是坐标平面上的原点)。 / p>
公共Getter / Setter方法或属性是有问题的,因为它们主要暴露对象状态(参见上面的第2项)。
公共方法应主要公开对象实例响应的逻辑操作(消息)。这些操作应该是原子的(例如,对于处于逻辑上一致的内部状态的对象,它不应该依赖于向其发送特定消息序列的外部actor)。对象状态应该是响应这些消息的结果,并且应该作为消息的副作用公开(例如,报告其位置作为要求移动的副作用的窗口是可接受的)
以上内容应大大减少对象的公共接口。
最后,如果你的对象有多个它响应的消息,你可能有一个重构的候选者:它真的是一个整体对象,还是一个离散对象的集合?当然,“不止一些”是一个非常主观(和上下文)的数字 - 我会把10-12作为一个合理的限制。
希望这有帮助。
有很多关于O-O设计,分析和建模的书籍。
答案 2 :(得分:8)
正如其他人所说的那样,当一个班级尝试做多件事而violates the Single Responsibility Principle时,这个班级太大了。
关于这个主题和其他主题的优秀书籍(我强烈建议任何开发人员使用)是Bob Martin的Clean Code。
答案 3 :(得分:6)
静态类(如Math)可能有很多方法。拆分它们会让人感到困惑。
答案 4 :(得分:4)
设计的一般准则:如果一个合理的人对一组事物的第一反应>可能合理地说“那太多了< thing> s!”,然后它太多了< thing> s。
答案 5 :(得分:2)
方法数量本身并不是一个可靠的指标。如果其中20个只是财产吸引人怎么办?
尝试更具体的指标,尽管这总是一个判断调用。有一个'代码味道'here列表。
答案 6 :(得分:2)
这都是相对的,但请查看single responsibility principle:
在面向对象的编程中, 单一责任原则 每个对象都应该有一个 责任,那 责任应该完全 由类
封装
我为SRP考虑过的经验法则:计算你的使用/进口/包含。如果你的班级有超过六个,那么你很可能违反了SRP。但这也是一个相对的想法。某些模式如外墙将违反此规则。例如。就像简化和隐藏复杂的子系统一样。
答案 7 :(得分:0)
这取决于您是否可以将类拆分为子类。
编辑:我的意思是你应该问自己“这个方法是否适用于这个类,还是属于一个子类?”
例如,
Class Animal - dog_bark()dog_bark()可以移动到名为Dog的类,并将该方法重命名为bark()
答案 8 :(得分:0)
取决于 如果你在Java中使用每个字段的get / set对,我并不感到惊讶。但如果这些方法中的每一种都是100多种野兽,那将是一种气味。
答案 9 :(得分:0)
从来没有一个类太大的东西,当PHP解释器读取你的代码时,它会编译成一个大的可执行代码黑色代码,因此拆分它们对性能没什么影响。
BUT:
当涉及到编程时,你不应该在一个类中真正需要40多个方法,并且应该分成这些方法。
实施例
class HTTP
{
/*
* Base functions for HTTP Fetching / transferring / Sending
* so when it comes to single responsibility this would be the the fetch / set in HTTP
*/
}
然后你会更具体地使用你的子类,如
class YoutubeUploader extends HTTP
{
/*
* This class is responsible for uploading to youtube only
*/
}
class YoutubeDownload extends HTTP
{
/*
* This class is responsible for downloading to youtube only
*/
}
class CronRunner extends HTTP
{
/*
* This class is responsible for Running your HTTP Cron Tasks
*/
}
否如果您没有BASE HTTP类,则必须在所有三个子类中定义方法以通过HTTP协议传输数据。
将您的课程拆分为单一职责可以提供更加结构化的框架,从而减少代码和结果。
每个人都已经提到了Single Responsibility Principal,但你应该真正理解它。
还有减少类中代码的方法,以此为例
class User
{
public function getUsername()
{
return $data['username'];
}
public function getPermissions()
{
return $data['permissions'];
}
public function getFirstname()
{
return $data['firstname'];
}
}
当你能做到时,这并不是真的需要:
class User
{
public function __call($method,$params = array())
{
if(substr(0,3,$method) == "get")
{
$var_name = substr(3,strlen($method),$method);
return $data[$var_name];
}
}
}
这将采用任何以'get'开头的方法来获取汽车,它会占用字符串的最后一部分并搜索数组。
答案 10 :(得分:0)
关于它的一点是在“Effective C ++”第3版中采用的:
“首选非会员,非朋友功能到会员功能”。这意味着你应该保持你的班级合理小,因为大班往往难以扩展(不能很好地扩展)
你也可以检查你的班级分支。如果您的课程包含“if's”或“switch'es”,则您的课程责任很可能已经解散。如果是这种情况,重构并将责任分解为较小的部分可能会导致较小的类别。
最诚挚的问候,
马尔钦
答案 11 :(得分:0)
一般来说,课程应该设计为做一件事并且做得好。现在,通过Math类的示例,它可以作为分隔实现的外观。或者它可以分成层次结构:
public abstract class Math
{
abstract Solve(IMathPayload);
abstract CanSolve(IMathPayload);
}
public class LinearMath : Math {}
public class DifferentialEquasionMath: Math {}
答案 12 :(得分:0)
我想遵循的一个策略是为每个数据模型对象创建一个“Handle”类。因为句柄只负责修改 该数据对象,它遵循SRP。如果我需要在数据对象修改之外创建类,至少我知道大多数代码已经符合SRP。