在设计新系统或了解其他人的代码时,有哪些迹象表明在设计阶段出现了问题?是否有寻找类图和继承层次结构的线索,甚至是代码本身,只是为设计检修而尖叫,特别是在项目的早期?
答案 0 :(得分:48)
对我来说最重要的事情是“code smells”。
大多数情况下,我对违反“良好做法”的事情很敏感。
类似的事情:
除了您从名称中想到的内容之外的其他方法(例如:默认删除零字节文件的FileExists())
一些非常长的方法(程序周围的对象包装符号)
在同一个枚举成员上重复使用switch / case语句(需要提取的子类的符号)
许多用于处理的成员变量,而不是捕获状态(可能表示需要提取方法对象)
一个有很多责任的课程(违反单一可怜原则)
成员访问的长链(这个很好,这个。其他很好,但my.very.long.chain.of.member.accesses.for.a.result很脆弱)< / p>
课程命名不佳
在狭小空间内使用过多设计模式
工作太辛苦(重写框架中已存在的功能,或同一项目中的其他地方)
拼写错误(任何地方)和语法(在评论中)或评论只是误导
答案 1 :(得分:18)
我会说OO设计糟糕的头号规则(是的,我已经犯过太多次了!)是:
其次是:
答案 2 :(得分:16)
无法正确进行单元测试。
答案 3 :(得分:12)
软件设计反模式
面向对象设计反模式
答案 4 :(得分:7)
这个问题假设面向对象意味着良好的设计。有些情况下,另一种方法更为合适。
答案 5 :(得分:5)
一种气味是具有硬依赖性/对其他对象的引用的对象,这些对象不是其自然对象层次结构或域相关组合的一部分。
示例:假设您有城市模拟。如果Person对象具有NearestPostOffice属性,则可能遇到麻烦。
答案 6 :(得分:3)
我讨厌看到的一件事是基类将自身向下转换为派生类。当你看到这个时,你知道你有问题。
其他例子可能是:
答案 7 :(得分:3)
在我看来,所有OOP代码都会在足够长的时间内退化为程序代码。
当然,如果你读了我最近的问题,你可能会理解为什么我有点厌倦了。
OOP的关键问题在于,您的对象构造图应该与您的调用图无关。
一旦解决了这个问题,OOP实际上就开始有意义了。问题是很少有团队知道这种设计模式。
答案 8 :(得分:2)
以下是一些:
答案 9 :(得分:2)
在一个很长的方法中,用#region / #endregion包围的部分 - 在我看过的几乎每种情况下,代码都可以很容易地被提取到一个新方法中,或者需要以某种方式重构。
过于复杂的继承树,其中子类执行非常不同的事情,并且彼此之间只是切线相关。
违反DRY - 每个子类都以几乎完全相同的方式覆盖基本方法,只有很小的变化。一个例子:我最近研究过一些代码,其中每个子类都覆盖了一个基本方法,唯一的区别是类型测试(“x是ThisType”vs“x是ThatType”)。我在基础中实现了一个采用泛型类型T的方法,然后在测试中使用它。然后,每个孩子都可以调用基本实现,传递它想要测试的类型。这从8个不同的子类中删除了大约30行代码。
答案 10 :(得分:1)
重复代码=做同样事情的代码......我认为根据我的经验,这是OO设计中可能出现的最大错误。
答案 11 :(得分:1)
对象很好创造了大量的OO设计。
答案 12 :(得分:0)
让所有对象继承一些基本实用程序类,这样就可以调用实用程序方法而无需输入这么多代码。
答案 13 :(得分:0)
找一位有代码基础经验的程序员。让他们解释一些有效的方法。
如果他们说“此函数调用该函数”,则他们的代码是程序性的。
如果他们说“这个班级与该班级互动”,他们的代码就是OO。
答案 14 :(得分:0)
以下是糟糕设计的最突出特点:
答案 15 :(得分:0)
当你不只是一个Money \ Amount类而是一个TrainerPrice类,TablePrice类,AddTablePriceAction类等等。
IDE驱动开发或自动完成开发。结合极端严格的打字是一场完美的风暴。
在这里你可以看到很多可能是变量值成为类名和方法名以及一般类的无偿使用。你还会看到所有原语成为对象的东西。所有文字作为类。函数参数为类。然后到处转换方法。你还会看到类似包装另一个类的方法,将一个方法子集提供给另一个类,只包括目前所需的类。
这样就可以生成近乎无限量的代码,如果您有可计费小时数,那么这些代码非常棒。当变量,上下文,属性和状态被展开为超显式和过度特定的类时,这会产生指数大灾难,因为这些事物迟早会成倍增加。把它想象成[a,b] x [x,y]。尝试创建一个完整的流畅界面以及尽可能多地遵循设计模式,可以进一步加剧这一点。
OOP语言不像某些松散类型的语言那样具有多态性。松散类型的语言通常以浅层语法提供运行时多态性,静态分析无法处理。
在OOP中,您可能会看到难以自动检测的重复形式,可以使用地图将其转换为更动态的代码。虽然这些语言的动态性较差,但您可以通过一些额外的工作来实现动态功能。
这里的交易是您可以节省数千(或数百万)行代码,同时可能会丢失IDE功能和静态分析。性能可以是两种方式。运行时多态通常可以转换为生成的代码。但是在某些情况下,空间非常大,除了运行时多态之外的任何东西都是不可能的。
对于缺乏泛型的OOP语言以及OOP程序员尝试严格键入动态松散类型语言时,问题更为常见。
如果没有泛型,你应该有一个A代表X = [Q,W,E]和Y = [R,T,Y]你会看到[AQR,AQT,AQY,AWR,AWT,AWY,AER ,AET,AEY]。这通常是由于担心或使用无类型或将类型作为变量传递而失去IDE支持。
传统的松散类型语言是使用文本编辑器而不是IDE创建的,并且通过IDE支持而失去的优势通常以其他方式获得,例如组织和构造代码以使其可导航。
通常可以将IDE配置为理解您的动态代码(并链接到它),但很少能够方便地正确支持它。
提示:这里的上下文是OOP在PHP中出现了可怕的错误,人们使用简单的OOP Java编程传统上已经尝试将其应用于PHP,即使有一些OOP支持也是一种根本不同的语言类型。
针对您的平台进行设计,尝试将其转换为您习惯的平台,设计以满足IDE或其他工具的需求,设计以满足支持单元测试等需要响起警钟,因为它与设计相差很大工作软件来解决给定类别的问题或给定的功能集。