Partitioning of Models with Faktor-IPS

Working with Associations: Derived Union

grund haus en
Figure 1. Composition Associations in the Base Model and Home Model

Let us look once more at the UML model with the inheritance relationships between the base model and the home model (figure above). There is a composition association between the cross-line classes Contract and Coverage on the one hand, and between HomeContract and HomeExtraCoverage / HomeBaseCoverage on the other. Our expectation is as follows:

  • A home base coverage and any number of home extra coverages can be added to a HomeContract, but no motor vehicle coverages, for example.

  • When a home base coverage or extra coverage is added to a HomeContract, it is also returned when requesting all coverages from the contract (i.e. those whose types are Coverage or subclasses of Coverage).

This expected semantics is not, however, contained in the model. The associations between Contract and Coverage, and between HomeContract and HomeBaseCoverage/HomeExtraCoverage, are initially independent of each other. An example illustrates this:

In the following code snippet we create an instance of HomeContract and an instance of HomeExtraCoverage and add the extra coverage to the home contract using the method addHomeExtraCoverage(…​). If we now ask the contract for its coverages using getCoverages(), we receive an empty list. If we ask the HomeContract for its extra coverages using getHomeExtraCoverages(), we get back, as expected, a list containing the extra coverage.

HomeContract homeContract = new HomeContract();
HomeExtraCoverage newExtraCoverage = new HomeExtraCoverage();
homeContract.addHomeExtraCoverage(newExtraCoverage);
homeContract.getCoverages();        // returns null
homeContract.getHomeExtraCoverages(); // returns an ArrayList containing newExtraCoverage as element

When we look at the code generated from the model, we understand why. The composition associations to Coverage, HomeBaseCoverage and HomeExtraCoverage are each represented as separate member variables in Java:

public abstract class Contract /* ... */ {
    private List<ICoverage> coverages = new ArrayList<>();
    public List<ICoverage> getCoverages() {
        return Collections.unmodifiableList(coverages);
    }
    // ...
}
public class HomeContract extends Contract /* ... */ {
    private HomeBaseCoverage homeBaseCoverage = null;
    private List<HomeExtraCoverage> homeExtraCoverages = new ArrayList<>();
    public HomeBaseCoverage getHomeBaseCoverage() {
        return homeBaseCoverage;
    }
    public List<? extends HomeExtraCoverage> getHomeExtraCoverages() {
        return Collections.unmodifiableList(homeExtraCoverages);
    }
    // ...
}

We can achieve the desired semantics by not managing the coverages in a member variable of the contract, but instead deriving the coverages of a contract from the other two associations. The following code snippet shows how this can be done:

public List<ICoverage> getCoverages() {
    List<ICoverage> result = new ArrayList<>();
    // if there is a base coverage, add it to the coverages
    HomeBaseCoverage baseCoverage = getHomeBaseCoverage();
    if (baseCoverage != null) {
        result.add(baseCoverage);
    }
    // now add all extra coverages
    result.addAll(getHomeExtraCoverages());
    return result;
}

This turns the Contract–Coverage association into a derived association. It corresponds to the union of the other two associations. Such types of associations are also referred to as "derived union" in UML. The following class diagram shows the model using the derived union in UML notation:

derived en
Figure 2. Derived Union Coverage

The remaining problem in our implementation is that the getCoverages() method can only be implemented this way in the home model in the subclass HomeContract, since it accesses the home-specific classes HomeBaseCoverage and HomeExtraCoverage. How can a contract then be queried for its coverages in a line-independent manner? We solve this by marking the Contract class as abstract and implementing the method only in the line-specific subclasses of Contract.

This is easier with Faktor-IPS: to mark the Contract–Coverage association as a derived union, open the editor for the Contract class and then the dialog for editing the association. In the dialog, check the checkbox as shown in the following figure.

derived union definieren en
Figure 3. Defining a Derived Union

The we mark the association in the home model as a subset of the derived union.

derived union definieren2 en
Figure 4. Defining a Subset of a Derived Union