1

I have a UML 2.5 class diagram with a lot of composition relationships.

I'm tying to implement them in Kotlin (I am new in Kotlin sorry):

class RuleScenarioState (val description : String){

    var action: RuleStateAction? = null

    var stateType : ScenarioStateType? = null

    var completeCriteria : StateCompleteCriteria? = null

    private class ComplexCompleteCriteria private constructor(val customCriteriaImplementation : String): StateCompleteCriteria()  {
    }

    private class ExpressionCompleteCriteria private constructor(val expression : RegulationExpression): StateCompleteCriteria() {
    }

    private class RegulationNodeCompleteCriteria   private constructor(val regulationNodeTreeId : UUID):  StateCompleteCriteria() {
    }

    private class CustomCompleteCriteria  private constructor(val customCriteriaImplementation : String): StateCompleteCriteria() {
    }

    private class CustomRuleStateAction private constructor(val customActionImplementationName : String): RuleStateAction() {
    }

    private class ClassificationRuleActionState  private constructor(val classificationExpression : RegulationExpression):  RuleStateAction() {
    }
}

Unfortunately I have no idea how this classes will be used, I just have a diagram which need to implement. I think that it is bad idea to create instances with intensive state manipulations as shown above, but how to assure one-to-one instances relationship? How to implement properly UML composition relationship in Kotlin?

greg-449
  • 109,219
  • 232
  • 102
  • 145
  • Is this your diagram? I wonder if the inheritance arrows are in the right direction: abstract classes rarely inherit form multiple concrete classes. Can you please check? Also, what is meant with the dashed "reference" link ? Last but not least: is there any reason to make the composed classes private to the scenario state? (The diagram does not say this) – Christophe Apr 23 '22 at 14:51
  • @Christophe no! This is not my diagram. And it is not UML 2.5 at my option, but still the legal syntax of plantuml.com tool – Ekaterina Ivanova iceja.net Apr 24 '22 at 09:55

1 Answers1

1

What does the UML model require?

I'm new to Kotlin as well. When you read about composition in this language, you must be aware of the difference between object composition, which simply means to have a property that is an object, and composition in the UML meaning, which is also called composite aggregation.

UML composite aggregation is a kind of association that ensures two things:

  • that a component instance (e.g. RuleStateAction) is exclusively owned by a single composite (e.g. RuleScenarioState);
  • that the composite (e.g. RuleScenarioState) has the responsibility for the existence and the storage of its components (e.g. RuleStateAction), and in particular that its components are destroyed should the composite be terminated.

How to implement it in Kotlin?

The first requirement means to declare a private property to the class, using private var or private val. You should also make sure not to leak the object to the outside word by returning it in a way or in another. This can be a tricky point in some cases and may require to clone the object.

The second requirement may be achieved by creating the components in the composite. Kotlin is garbage collected, so if only the composite knows about the component, once the composite is no longer used, so is its component (you could also consider making it closeable, but let's not add unnecessary difficulty ;-)

Several unrelated remarks:

  • According to your design you should use some abstract classes. You seem to have avoided them in your code, but they are essential for this design to work. So you'd have a private var that is initialized with an instance of a concrete class inherited from the abstract class.

  • your diagram tells nothing about multiplicity of components. If it's only only one there is nothing special to add. But if it is many, you'll have to consider collections.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • I have read your post. First my guess that this https://gist.github.com/iva-nova-e-katerina/e51ca00e3f971b21a97bdab74d032f76 is the best implementation of diagram. But I am not sure because: 1) you are the only guy in the Internet who believe that Class Diagram specify the composition of objects. Even https://www.baeldung.com/java-composition-aggregation-association doesn't care about objects lifecycle and accessibility. 2) probably some of my inner classes and inner enums should be also private somehow – Ekaterina Ivanova iceja.net Apr 24 '22 at 10:25
  • PS: I am not sure that "that a component instance (e.g. RuleStateAction) is exclusively owned by a single composite" please take a look at baeldung code https://github.com/eugenp/tutorials/blob/master/core-java-modules/core-java-lang-oop-patterns/src/main/java/com/baeldung/relationships/composition/BuildingWithDefinitionRoomInMethod.java component's instance may be extracted and used outside the composite class - BuildingWithDefinitionRoomInMethod – Ekaterina Ivanova iceja.net Apr 24 '22 at 10:33
  • @CatherineIvanova Maybe Baeldung misunderstood UML composition: my statements refer almost completely to the UML 2.5.1 specifications related to the black diamond used. If an object can be referred at the same time in several places, composition should not be used: a simple association would be more accurate. It is possible also that the leaking of objects is not taken so literally in communities using reference semantic for objects (e.g Java, Kotlin, Swift, …) and that do not offer easy cloning features. – Christophe Apr 24 '22 at 11:01
  • This topic has caused a lively debate, could you provide a link to the section and paragraph of the UML 2.5.1 specification? If you're right, it remains for me to make all classes and enums inner and private, with the exception of the RoleScenario class, so I will restrict instantiation and references to instances of component classes this way. – Ekaterina Ivanova iceja.net Apr 24 '22 at 11:18
  • @CatherineIvanova Chrsitophe is not right in insisting that UML composition implies a lifecycle depency (ownwership). In fact, as explained, e.g., in https://stackoverflow.com/questions/885937/what-is-the-difference-between-association-aggregation-and-composition/35214676#35214676, the UML spec states that a composition often has such a lifecycle depency, but it also explains that there are cases of composition where the component can survive the destruction of the composite. – Gerd Wagner Apr 24 '22 at 11:50
  • @CatherineIvanova The exact paragraphs can be found on P.112 of the freely downloadable specs on the [OMG's website](https://www.omg.org/spec/UML/2.5.1/About-UML/). In the middle of the page you can find the exact definition of composite aggregation, and the first sentence bellow the table completes the definition. – Christophe Apr 24 '22 at 11:57
  • @GerdWagner the current specs say: "Composite: Indicates that the Property is aggregated compositely, i.e., the composite object has responsibility for the existence and storage of the composed objects" and "Composite aggregation is a strong form of aggregation that requires a part object be included in at most one composite object at a time. If a composite object is deleted, all of its part instances that are objects are deleted with it." - Thiss seems to me a strong explanation. – Christophe Apr 24 '22 at 12:00
  • It does not prevent of course a component being reassigned as long as it is owned by a single composite at any given moment in time – Christophe Apr 24 '22 at 12:00
  • @Christophe great sorry, but could you give me a pages numbers of both P.112 and " "Composite: Indicates that the Property is ...." ?? I am lost :( – Ekaterina Ivanova iceja.net Apr 24 '22 at 12:16
  • @CatherineIvanova P.112 was supposed to mean page 112. The sentences between double quotes are copy pasted – Christophe Apr 24 '22 at 12:29
  • @CatherineIvanova On page 112, they also say "A part object may (where otherwise allowed) be removed from a composite object before the composite object is deleted, and thus not be deleted as part of the composite object". In conclusion: a part object may or may not be deleted when its composite object is deleted. I don't know why Christophe (and others) are ignoring this statement. – Gerd Wagner Apr 24 '22 at 13:03
  • @Gerd Wagner this statement means nothing, it is about inner lifecycle of part-object. As for me most important that Class Diagram cares about objects lifecycle and accessibility. I can manage the accessibility of types when designing the classes. – Ekaterina Ivanova iceja.net Apr 24 '22 at 13:09
  • @Christophe it seems you are right. A lot of examples of composite relationship implementation I have found across the Internet does not restrict the objects following UML 2.5.1 specification. I need to discuss with diagram author. Thank you! – Ekaterina Ivanova iceja.net Apr 24 '22 at 13:11
  • @GerdWagner I think you misunderstand my point.My point is that the part can't be owned by two composites AT THE SAME TIME.Leaking the object puts you at risk of having this situation; not leaking it clearly prevents the issue. Of course if the ownership is transferred to another object, there is no conflict (i.e. the component can survive the composite that created it),but only under the condition that it is "removed from the composite before". So leaking the object and removing it is ok, leaking it but keeping it, would require extra caution would be required to avoid the multiple ownership – Christophe Apr 24 '22 at 17:34
  • But that's not what you say in your answer where I read "components are destroyed should the composite be terminated". Ownership doesn't have to be transferred to another object. The component can also be "free" (for some time). Like an engine as an exclusive component of a car can be removed and stored for some time, without immediately installing it in another car. – Gerd Wagner Apr 24 '22 at 22:03
  • @GerdWagner if a component is set free or its ownership transferred, it’s no longer a component of the composite that is going to be destroyed. There is no contradiction between the two statements. It’s just a constraint on the sequence of operations: the transfer must happen before the destruction. If taken strictly, leaking the reference prevents de facto this to happen. This being said, I agree that this perticular UML clause was clearly not written with garbage collected languages in mind. A revision of the wording in the specs would greatly help to reach consensus. – Christophe Apr 25 '22 at 06:43