答案 0 :(得分:4)
答案 1 :(得分:2)
[编辑以供进一步说明]
对系统建模是使用建模语言以正式方式描述它,在某些情况下,遵循一些通用准则。在这种情况下,您建议使用UML(请参见UML Specification)。
UML图可以分为三类:
作为建模者,您需要确定要应用的目标所需的图。
在您的问题中,您说您正在寻找一种对交互进行建模的方法。这属于行为类别。但是,您在结构类别中提供了示例代码和建议的类图。
话虽如此,您建议的图表是否正确?我会说这是不准确和不完整的(但不一定是不正确的)。让我进一步解释一下。
在建议的图中,您有四个类别:ServiceContract
,StorageContract
,QuizContract
和SignatureContract
。您已在类之间绘制了一种关系,称为 dependency 。这种依赖关系具有特定的类型:用法(由«use»关键字表示)。在UML中这意味着什么?
UML中的依赖关系被定义为一种关系,其中“ 没有供应商,客户的语义就不完整”(UML规范的第7.7.3.1节) 。此外,使用依赖关系被定义为一种关系,其中“ 一个NamedElement需要另一个NamedElement(或一组NamedElements)以实现其完整实现或操作”(第7.7.3.2节)
因此,如果我们将这些定义应用于您建议的图表,则您可能会阅读ServiceContract
与StorageContract
之间的关系,因为“ ServiceContract
使用StorageContract
”。但没有别的。使用此图,您不知道ServiceContract
如何使用StorageContract
,如果它使用多个StorageContract
实例,依此类推。
由于您知道这些类之间的关系,因此应该使用更准确和完整的图表。
第一步是使用关联而不是依赖性。在UML中,关联被定义为“ 在类型实例之间可能发生的语义关系”。并且您知道在类图中正在建模的类之间的语义关系。因此,使用关联会更有意义。
关联 用实线表示(实际上,UML规范说可以绘制为菱形,但是对于二进制关联,它通常表示为用实线绘制)。因此,让我们开始将图表更改为新图表。在下图中,您可以看到四个具有关联关系的类(仍然不完整):
现在有了关联,我们需要进一步定义它。协会有名字吗?可以以两种方式读取关联吗?我们知道关联两端的多重性值吗?协会的两端是否有矛盾?
在此示例中,我们不需要关联的名称,似乎可以以两种方式读取关联,并且多重性值在所有末端均为1。然后,我们不添加任何与这些问题有关的图表。但是约束呢?
让我们看一下源代码。当您放置此内容时:
contract ServiceContract {
constructor (address _storeC, address _quizC, address _signC) {
StorageContract storeC = StoreContract(_storeC);
QuizContract quizC = QuizContract(_quizC);
SignatureContract signC = SignatureContract(_signC);
}
}
您可以将其表示为“ ServiceContract
具有(拥有)名为storeC
的属性,该属性的类型为StoreContract
”,依此类推。关联中的所有权由一个小的实心圆(称为 dot )表示,该直线与所拥有的Classifer相交。您也可以添加拥有所有权的属性的名称(第11.5.4节)。此时,该图是这样的:
(请参见the answer from Thomas Kilian)
由于我们无法从源代码推断属性的可见性,因此我们可以将其设为未定义(否则,可以在公共名称的属性名称之前使用+
符号{{1 }}代表私有财产,-
代表受保护财产,#
代表包裹)。
我们还可以在~
的分类器中显示属性,而不是在关联中拥有的分类器的末尾显示属性。看起来像这样:
UML规范(第9.5.3节)允许两种样式,并且也不强制执行任何约定。但是,它提到了常规建模场景的约定“ ”,即类型为一种Class的属性是Association端,而类型为DataType的属性不是”。
该图符合UML规范,并且描述了您拥有的系统,因此是正确的。
ServiceContract
的分类器,具有三个属性:
ServiceContract
的属性,其类型为名为storeC
的分类器。StorageContract
的属性,其类型为名为quizC
的分类器。QuizContract
的属性,其类型为名为signC
的分类器。请记住,作为建模者,这是否足以满足您的目标是您的选择。
从源头上我可以说上一张图仍然不完整且不准确。为什么?
SignatureContract
拥有的分类器是否被拥有以将一组拥有的分类器的实例组合在一起。在这种情况下,是否拥有的分类器共享相同的范围。可以提高准确性。首先,我们将把操作(功能)添加到图中:
[注意:您也可以将_constructor_添加到操作中。]
我猜这些函数是公共的,因此我在每个操作名称的开头都包含了ServiceContract
修饰符。
为了准确起见,在我看来+
将ServiceContract
,StorageContract
和QuizContract
分组在一起,以便提供通用的分类器来访问某些操作(功能)。如果真是这样,那么我们在谈论的是聚合。在UML中,聚合定义为一种关联,其中“使用一个实例将一组实例分组在一起”(第9.5.3节)。
聚合可以分为两种类型:共享(或者在规范的先前版本中通常称为 aggregation )和 composite (或在规范的早期版本中通常称为 composition )。
UML规范或多或少地提供了某种语义,以表示聚合类型为 composite 的含义:“ 复合对象负责存在和存储对象。组成的物体”。
让我们说,在您的情况下,SignatureContract
,StorageContract
和QuizContract
的存在和存储是SignatureContract
的责任。那么在这种情况下,您有一个复合聚合,用黑色菱形表示:
它被读为“ ServiceContract
由分类器类型ServiceContract
的自有属性,称为StorageContract
”,依此类推。
请记住,使用复合类型的聚合,您是说storeC
对象负责存在和存储。这意味着无论何时{/ {1}}的实例被删除/销毁,相关的ServiceContract
,ServiceContract
和StorageContract
也必须被销毁。
如果不是这种情况,并且鉴于关联仍与聚合定义匹配,那么唯一可用的其他选择是必须共享。 UML规范没有明确提供 shared 聚合的确切语义,而使应用程序区域和建模者具有提供这些语义的责任。
因此,如果QuizContract
,SignatureContract
和StorageContract
独立于QuizContract
存在,并且如果您同意SignatureContract
汇总这些根据UML规范中定义的对象,您必须使用共享聚合。
共享的 聚合由分类器关联末尾的空心菱形表示,聚合其他分类器。这就是它的样子:
此图可以读为:
ServiceContract
,ServiceContract
,ServiceContract
和StorageContract
。QuizContract
汇总了三个拥有的属性:
SignatureContract
,类型为ServiceContract
。storeC
,类型为StorageContract
。quizC
,类型为QuizContract
。signC
有一个需要三个参数的构造函数:
SignatureContract
的ServiceContract
。_storeC
的address
。_quizC
的address
。_signC
具有三个公共功能:
address
,它需要一个类型为ServiceContract
的自变量storeData
,但不返回任何内容。bytes32
,它需要一个名为data
的类型getAnswer
的参数,并返回bytes32
数据类型。question
,它需要一个bytes32
类型的名为data的参数,并返回一种sign
数据类型。请记住,对于您想要的目标,此最终图表可能太详细了。作为建模者,您有责任决定是否在图表中包括或不包括一些细节。
答案 2 :(得分:0)
虽然花一些时间了解应该为 UML 中的特定 Solidity 关系(inheritance、组合等)使用什么确切的箭头可能是件好事,但总体趋势是让标准工具来关注这一点。
>有sol2uml UML生成器https://github.com/naddison36/sol2uml
已在 https://etherscan.io 上使用
例如USDT https://etherscan.io/viewsvg?t=1&a=0xdAC17F958D2ee523a2206206994597C13D831ec7 (见下图)
所以不要花时间手动绘制线条,使用更明智的工具为您更快地完成。