2

MyClass给定一个通过类与 API/Datalayer/external-something 通信的 Objective-C 类ConnectionMyClass应该(取决于周围的拱门)Connection在构造函数中接收和实例,或者Connection应该将实例传递给每个需要联系。这种方式MyClass可以封装应用程序逻辑并且保持对连接细节的无知。

MyClass要在不同的外部组件中重用逻辑或进行单元测试MyClass,使用协议 ( ConnectionProtocol) 而不是类是正确的Connection。这样,不同的类(比如 ConnectionHttp、ConnnectionAPI2、ConnectionTestingEmulateProxyIssue 等)MyClass只要实现ConnectionProtocol.

现在,假设开发人员有一段代码在 , 中重复MyClassMyOtherClass并执行一系列操作ConnectionProtocol。这违反了DRY原则,因此是不可接受的。

  1. 由于MyClassMyOtherClass和 不共享公共基类(NSObject 除外),因此开发人员不能简单地将功能合并到基类中。

  2. 添加一个方法再次ConnectionProtocol违反DRY,因为需要在ConnectionProtocol.

  3. 使该方法成为@optional成员ConnectionProtocol仍然不起作用,因为

    • 该方法经常使用,并且需要在每个实现中实现,并且
    • 方法逻辑特定于应用程序,而不是违反SoC的连接。
  4. 开发人员考虑向 NSObject 添加一个类别,该类别检查传递的对象是否实现协议ConnectionProtocol,然后执行所需的操作。这有缺点:

    • NSObject 的方法空间被使用该类别的文件中的所有对象污染,
    • 错误调用类别方法的错误在运行时被捕获,并且开发人员出于某种原因选择了强类型语言
  5. ConnectionProtocol使用类别进行扩展。这不违反 DRY 原则并尊重 SoC。然而,它确实违反了 Objective-C 规范。

    @implementation id< ConnectionProtocol > (AppLogicMethods)
    
    -(void)specialMethod:(NSObject*)myParam
    {
        // Do Stuff  
    }
    
    @end
    

如何在不违反DRY、尊重SoC并满足 Objective-C 限制的情况下解决这个问题?

4

2 回答 2

2

这违反了 DRY 原则,因此是不可接受的。

DRY 不是无懈可击的自然法则。在美国大多数州,这甚至不是重罪。它是一个有用的设计指南,应该与其他有用的设计指南(例如简单性和避免SAAAD )进行权衡。我已经看到许多项目变得过于复杂,因为害怕重复几行琐碎的代码。清晰比简洁更重要。魔术比 WET 更糟糕。

也就是说,DRY 是一个有用的指导,我认为我们可以在此处适当地合并它。

现在,假设开发人员有一段代码在 MyClass、MyOtherClass 中重复,并使用 ConnectionProtocol 执行一系列操作。

这表明存在独立于实际传输的更高级别的操作(“重复的代码块......并使用 ConnectionProtocol 执行一系列操作”)。这表明您在错误的级别进行抽象。您有一个较低级别的传输(“HTTP”),并且您有一个称为“连接”的更高级别的东西来管理该传输。所以应该有一个具体的类ConnectionHAS-A <Transport>,并且MyClass会 HAS-A Connection

也就是说,我创建这个<Transport>协议会很慢。我将从Connection包含传输逻辑的类开始。如果我必须解决的唯一问题是单元测试,我可能只是为此进行子类Connection化而不是注入复杂性。如果出现非测试问题,那么我会重构以添加额外的层。过早添加太多层是使代码库过于复杂的常见方法,而复杂性是鲁棒性的最大敌人,而不是重复自己。

附带说明:您使用类方法打包公共代码的答案也是一种非常合理的方法,并且对于某些用途可能更简单。

于 2013-10-15T23:00:12.507 回答
0

创建了一个“实用程序类”,ConnectionProtocolmyParam被传递到其中。

@implementation ConnectionProtocolAppLogicMethods

+(void)specialMethod:(NSObject*)myParam connection:(id<ConnectionProtocol>)connection
{
    // Do Stuff
}

@end
于 2013-10-15T21:31:33.393 回答