如何在 UML 中可视化协议和扩展?

How to visualize Protocols and Extensions in UML?

使用 UML 接口来可视化 UML 中的 Swift 协议似乎是合理的。但是我应该如何可视化为特定协议提供默认实现的扩展?我应该只使用继承自该协议的 class,例如 <<extension>>ProtocolName 吗?

扩展存在于某个 class 的范围内,只是向其添加了一些功能。所以我会将扩展名表示为 subclass(最终打包可能是首选)。为了表明它是一个扩展,我会使用刻板印象。对扩展的 class 的依赖在某种程度上是可选的,因为在上下文中它是一个命名约定。

如果扩展将另外遵守某些协议,您只需将实现关系添加到相应的接口 classes。

这是一种表达方式。由于没有用于扩展的原生 UML 构造,您可以相对自由地在这里发明自己的惯用语。

简而言之

Swift 协议原则上是一个 UML 接口:class 不从 interface/protocol 继承任何东西,但必须实现 interface/protocol 承诺的功能.

协议扩展改变了这种语义等价:协议扩展可以提供一致性 classes 将继承的特性。这与 UML 接口不兼容,对应于 semantic of an abstract class。但是使用 abstract classes 会使多重继承变得混乱。刻板印象《协议》似乎更可取。

更多解释

协议

未扩展的swift protocol确实对应于UML接口,尽管措辞略有不同:

Swift: A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements.

对比:

UML: An Interface is a kind of Classifier that represents a declaration of a set of public Features and obligations that together constitute a coherent service. An Interface specifies a contract; any instance of a Classifier that realizes the Interface shall fulfill that contract.

Class 扩展

有不同的种类extensions。 class 扩展将功能添加到它们扩展的 class 中。如果扩展名出现在同一个文件中,它甚至可以访问 class.

的私有成员
class MyClass {
    func hello()->Void { print ("Hello, World !"); }
}
var c = MyClass()
extension MyClass {  // first extension
    func hellobye() -> Void { hello(); print(" Good bye!"); }
}
extension MyClass {  // second extension
    func bye() -> Void { print("Au revoir!"); }
}
c.hello()      // the object has all the features of class + extension
c.hellobye()   // even if it was defined befor the extension    
c.bye()

扩展名没有明确的名称:它只是重新定义了原始类型,class 的行为就好像初始定义和扩展名是相同的 classifier,只是分开了在源代码中:

  • 如果扩展和初始 class 在同一个包中定义,在 UML 中表示它的最干净的方法是在 UML 图中丰富初始 class。
  • 如果扩展是在另一个包中定义的,您可以将完整的扩展集表示为与自己的 class 相同的 class,以及将两者组合的合并包。由于扩展工作需要原始 class,因此您还可以显示两者之间的依赖关系。或者,您也可以想到 «class extension» 刻板印象。但同样,由于 UML 唯一命名约束,将所有扩展分组到包中的相同 class。

协议扩展

协议扩展改变了底层协议的性质。虽然原始协议是一个没有任何实现的接口,但扩展协议将提供一些实现:

protocol MyProto {
    var v1:String { get  }
    func op1() -> Void
    func op2() -> Void
}

class Test : MyProto {
    var v1:String = "abc"
    func op1() -> Void { print("Op 1"); }
    func op2() -> Void { print("Op 2"); }
}

extension MyProto {
    var dev1:String { get { return "de"+v1; }}
    func combo() -> Void { op1(); op2(); print("Combo 1 and 2"); }
}

var test = Test()
test.combo()
print (test.dev1);

在 UML 中,扩展协议将对应于一个 «abstract» class,即 class 由于缺少某些功能而无法直接实例化,但可能具有某些功能明确定义的是继承的。 UML 不完全支持这种情况,因为没有将接口转换为抽象的建模方法 class:

最简洁的方法是使用 UML 配置文件,将构造型 «protocol» 定义为 «abstract» classes 的特殊形式。然后将按照上面对 classes 的解释处理协议扩展,在提到 «class extension» 的情况下使用 «protocol extension»