什么时候课程太大了?

时间:2010-12-02 19:12:28

标签: oop

我倾向于创建具有30-40(或更多)方法的非常大的类。有多少方法太多了?是否有任何“气味”或经验法则可供使用?

13 个答案:

答案 0 :(得分:45)

第一步是坚持Single Responsibility Principle。如果你不能用一句话说出你班级的作用,那么它可能会做得太多。

一旦你缩小了范围,我不知道只要你的方法don't do too much,方法的数量真的很重要。

答案 1 :(得分:23)

我会咬人的。如果没有做太多的事情,只要涉足O-O设计深水的浅层边缘,我将通过几条经验法则:

  1. 静态属性非常值得怀疑。强烈质疑他们是否真的需要。

  2. 类的大多数属性/属性应该是私有的(只能由对象实例访问)或受保护,只能由类或派生类(子类)的实例访问。

  3. 如果某个类的属性/属性对普通公众可见,则它很可能是只读的。在大多数情况下,对象实例的状态应该仅通过响应一个方法来改变,要求它做一些有用的事情(例如,你请求一个窗口自己移动,而不是显式设置是坐标平面上的原点)。 / p>

  4. 公共Getter / Setter方法或属性是有问题的,因为它们主要暴露对象状态(参见上面的第2项)。

  5. 公共方法应主要公开对象实例响应的逻辑操作(消息)。这些操作应该是原子的(例如,对于处于逻辑上一致的内部状态的对象,它不应该依赖于向其发送特定消息序列的外部actor)。对象状态应该是响应这些消息的结果,并且应该作为消息的副作用公开(例如,报告其位置作为要求移动的副作用的窗口是可接受的)

  6. 以上内容应大大减少对象的公共接口。

    最后,如果你的对象有多个它响应的消息,你可能有一个重构的候选者:它真的是一个整体对象,还是一个离散对象的集合?当然,“不止一些”是一个非常主观(和上下文)的数字 - 我会把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。