3

I already have written my code, but for my personal knowledge I would like to know how could I have modelized it.

Here we go: an user can have many profiles, each one tied to one and only application. A profile defines user's rights within the application: same user can be administrator in the scope of app1, at the same time a basic user of app2...

Pseudo-code looks like that:

public class User
{
   public string UserId { get; set; }

   // Only store the AppId of application but it could be an IDictionary<Application, UserProfile>
   public IDictionary<string, UserProfile> Profiles { get; set; }
}

public enum UserProfile 
{
   BasicUser,
   Administrator,
}

public class Application
{
   public string AppId { get; set; }
}

As you can see UserProfile is just an enum, while Application could be a simple string but I need a class here.

How would I represent these 3 entities on a class diagram? I think that a class association is not a good option, as it wouldn't have any property. But I don't know what else is possible.

paradise
  • 336
  • 2
  • 15

3 Answers3

2

I don't see any n-ary association in your code.

What you sketched looks like this:

enter image description here

Application isn't associated to anything so its an orphan.

Properties can be represented in different ways and are language specfic. The above would be used for C#

qwerty_so
  • 35,448
  • 8
  • 62
  • 86
  • Thank you for this effort. If `profiles` was a dictionary of `` instead of ``, how would these 2 classes be related? – paradise Apr 08 '20 at 15:11
  • 1
    In that case you draw a dependency towards `Application` just like with the enum. – qwerty_so Apr 08 '20 at 17:05
  • Your model doesn't capture the relationship between `User` and `Application` as an association (class). Also, duplicating a property in a class rectangle in a C# implementation model is a very ugly/noisy approach. This can be expressed in a much better way using <> attribute stereotypes, see https://stackoverflow.com/questions/28139621/shortcut-for-denoting-or-implying-getters-and-setters-in-uml-class-diagrams/28141950#28141950 – Gerd Wagner Apr 18 '20 at 08:52
  • @GerdWagner You may be right. My intention when answering questions like this is not to give a fully worked out model (which is impossible without extensive discussions). It's more that I try to point into some direction. Looking at Christophe's answer: I honestly am too lazy to elaborate that far. I can only guess that this was asked for some kind of exam and the OP is out to write these exams. Pareto rules. – qwerty_so Apr 18 '20 at 09:22
2

Dictionaries matter !

At first I was thinking like qwerty_so, except that:

  • there is a qualified association with UserProfiles: it is implemented with with an IDictionary, where a string is used to qualify the User.
  • this association is navigable in one direction, since you can go easily from the User to UserProfile, but it's much more difficult to go the other way round (you can, but you have to iterate through all the uses).

So the diagram could look like:

enter image description here

Some additional remarks about this diagram:

  • There is no UML standard for C# properties, which are a mixture between an UML property and an UML operation (via the implicit getter and setter). The usual practice is to use an UML profile that defines the stereotype «property». My own preferred option is to keep it in the properties of the class (like here or here), since that is the semantic of a C# property. However, some argue that this stereotype should be considered as a specialisation of an UML operation (like here and in qwerty's answer), which is also a valid argument, especially if you define custom getters and setters.
  • Be careful with the multiplicity in qualified association, since it applies to the User qualified with the string. So 0..1 UserProfile is for one specific combination of User and string. So it is in reality 0..* if we would consider the unqualified User.

Model transformation

We have to keep in mind that a given implementation could correspond to different designs. The implementation is how you write the code, and the design is how you see the things.

So we can transform this first reversed engineered model to match your thought model. Only you can tell how you want to see the things that led you to your current implementation.

For example, you may not be so interested in navigability, and you may set the focus on the many-to-many association between the unqualified User and UserProfile. With this approach, the string that was used as qualifier would become a property of the association class:

enter image description here

Be aware nevertheless that it's a transformation. Qualified association and one-to-many is not the same thing and the two models do not mean exatly the same thing.

And here comes the n-ary association !

Now the key question is the purpose of the string property in this association class. I strongly suspect that it's in fact the id of your Application (I let you confirm in the comments).

If it's the case, we would have an association between the association class and the Application. And we could remove the string property from the association class because it would then be redundant.

But an association class that is itself associated with some other class, shows that there in fact an n-ary associaton (ternary here). So, we could make this explicit:

enter image description here

Now you have an n-ary association. You could even have an association class behind it, if there would be additional properties to associate with each triplet (User, Application, UserProfile).

But be aware that this diagram is less precise. It is for example more difficult to indicate navigability constraints in an n-ary association. And it does no longer fully correspond to your implementation: this model suggest that you could find users starting from an application, whereas in your implementation it's more difficult.

Conclusion/advices

Personally, I find n-ary association difficult to work with and I prefer to decompose them in a set of classes and binary associations (and association classes when necessary): This allows to remove a lot of ambiguity and gives tighter control. I can only recommend you the same approach.

Consider also your implementation: if the implementation represents your view of the world, then use the qualified association, because it's the UML equivalent to the dictionary.

However if the ternary association is your view of the world, you may sooner or later have to review your current implementation. Probably you'd extract the profiles to make an own class of it.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • 1
    I like your n-ary association, it’s pretty much like I imagined the design while asking my question. But you pointed that it doesn't correspond precisely to my implementation, and I think you're right! Navigability is the key. To match this diagram I should have a Dictionary of Users/Profiles in my Application class as well. As it won't be the case, the qualified association seems to be the best candidate. Thank you. – paradise Apr 09 '20 at 21:35
  • And yes, on your 1st diagram the `:string` is the same as `AppId`. I edited my question to improve Ids' naming. – paradise Apr 09 '20 at 21:42
  • Your model doesn't capture the relationship between `User` and `Application` as an association (class). Also notice, that a "view of the world" rather corresponds to a (logical) design model and not to the implementation choice of using a map/dictionary for implementing a multi-valued property. – Gerd Wagner Apr 18 '20 at 08:57
  • @GerdWagner In the n-ary association, the User is always associated with Application together with a UserProfile. This means that you can find applications for a user or users for an application. Behind the n-ary association, you may also very well have an association class, exactly as behind a binary association. I didn’t show it, since the current code has no need for it. And indeed, if there would be (but no evidence in the code) profile-independent properties per application (e.g user preferences), we could consider an additional binary association between user and application. – Christophe Apr 18 '20 at 09:58
  • @GerdWagner I can fully agree with your second remark. In fact I used a stepwise approach to give OP the opportunity to chose between an implementation model and a design model (assuming nevertheless that the second would be more useful). – Christophe Apr 18 '20 at 10:07
2

Your C# property User::Profiles implements a many-to-many association class between User and Application having a UML property like role: RoleEL, where I have replaced your enumeration name "UserProfile" with "RoleEL" for better readability (notice that "EL" stands for "enumeration literal"). This is shown in the following class diagram:

enter image description here

I think this design model is simpler and more natural than the models suggested by @qwerty_so and @Christophe.

Notice that the model by qwerty_so is not a (logical) design model, but rather an implementation model, as it does not display the relationship between User and Application, but rather keeps it burried in the code of the profiles property. Also, it unncessarily duplicates a UML property (using the confusing stereotype keyword «property»).

Gerd Wagner
  • 5,481
  • 1
  • 22
  • 41
  • I like this too. Now I don't know which one to choose between you proposal and @Christophe 's first one, under reserve of switching `UserProfile` and `Application`. – paradise Apr 17 '20 at 08:26
  • @paradise: Notice that @Christophe 's models do not properly model the relationship between`User` and `Application` as an association (class). – Gerd Wagner Apr 18 '20 at 08:47
  • 1
    @paradise: Also notice that my model allows extending the user-app profile by adding further attributes (e.g. *usage time*). – Gerd Wagner Apr 18 '20 at 09:44
  • 1
    Yes this is also a nice model. I’d probably have started there for forward engineering. In my answer I was tempted to show the second step like this. But I didn’t because the question was about reverse engineering and I wanted stick close to that thought process. In addition, in the domain of user management, it often appears that application roles are more complex that just an enum (e.g. dynamically created, associated with features or data constraints). This model wouldn’t aknowledge in the same fashion the existence of a role as a user-independent entity. But +1 since it is a valid alternat – Christophe Apr 18 '20 at 10:27