6

I want to model a file system which contains both files and directories, and directories can contain either files or other directories.

This is what I have reached so far:

My simple file system class diagram

In OOSE book, however, a similar model is presented:

class diagram for file system presented

Now I have two questions:

  1. I wonder why the author did not use an Interface to represent the abstract type FileSystemElement? Isn't using an interface for this type correct?

  2. As we know, files and directories must have names with similar constraint (e.g. maximum length of 256 characters). Therefore, it would be nice if I model this in the FileSystemElement. But an interface cannot have a abstract attribute, so I have to repeat name attribute in both Directory and File classes. Is there any better workaround for this problem?

Isaac
  • 265
  • 2
  • 6
  • 11
  • 1
    Regarding your first question: If `Directory` and `File` were supposed to be the *only* possible subtypes of `FileSystemElement`, you could not enforce that constraint with an interface as the supertype; anyone is allowed to implement an interface they have access to. You would instead need an abstract class with a constructor that has package visibility (`~` in UML). So if your package cannot actually deal with *any* kind of `FileSystemElement`, but expects only the subtypes that you defined yourself, you'd need an abstract base class. – stakx Nov 29 '14 at 09:29
  • @stakx: I didn't know that could be a concern. Thanks for that. – Isaac Nov 29 '14 at 20:02

5 Answers5

4

Isn't using an interface for this type correct?

Using an interface in this case would work, but you would have to duplicate behavior between Directory and File (like having a maximum of 256 chars for the name). You would be better off making FileSystemElement an abstract class (assuming your language of choice supports it) Which also answers your second question : an abstract class can provide default behavior for its children. You can just declare the Name property inside the parent class, with the associated validations, etc. That way, Directory and File will inherit the property and the behavior. You won't have to redefine anything in the Directory of File class. No code duplication.

marco-fiset
  • 8,721
  • 9
  • 35
  • 46
1

I wonder why the author did not use an Interface to represent the abstract type FileSystemElement? Isn't using an interface for this type correct?

It would be correct, in so far as a valid UML model, as would be using an abstract base class. The design decision depends on other factors, quite often tied to implementation language.

But an interface cannot have a abstract attribute, so I have to repeat name attribute in both Directory and File classes. Is there any better workaround for this problem?

An interface can have attributes, and they are assumed to be abstract. How these abstract attributes are translated to real code will use different idioms for each different implementation language, and often different idioms between different users of the same implementation language. At the UML level, it's not a restriction at all.

As we know, files and directories must have names with similar constraint (e.g. maximum length of 256 characters). Therefore, it would be nice if I model this in the FileSystemElement.

There is no reason why you cannot put a UML constraint on an attribute of the interface. { Name.Length <= 256 } can be put on an attribute owned by an interface just as well as you would an attribute owned by any other classifier. How it would get implemented will differ both in the implementation language and in implementation strategy - perhaps you have a validate function which takes an instance of the interface, asks it for the name and tests the length. Translating UML constraints to code doesn't necessarily follow the 'throw an exception if you try to call the getter' pattern, though it often does.

It is possible that the author of the OOSE book had some implementation strategy in mind, and therefore uses a concrete class. Quite what I'd do depends on what else the classes are for - for example, if they are just placeholders for path fragments, and rely on something else to create a stream which opens the file, they you can test them completely without having an interface to mock, so I'd not bother with the extra layer of abstraction. If they had direct operations to return streams or perform other file system operations, I may well use an interface so they can be mocked for testing. Neither is correct, and which is a better fit for the requirements can't be determined from two very small UML diagrams.

A quick scan through the OOSE book you link to confirms that it is talking about class diagrams much in the same terms as you would ER-Diagrams and considering representing relationships between nouns, not what the objects do. I would caution that if you are considering nouns in static relationship then you are talking procedural rather object oriented code - perhaps that is why you are finding that the model presented in the book is concentrating on concrete types with attributes rather than an interface of operations. Or perhaps it is just trying to demonstrate different types of associations and it's not worth looking too deeply at it!

Pete Kirkham
  • 1,798
  • 14
  • 15
0

I like the fact that you added an association between the file and the directory (although you did not specify multiplicity). Now as per your questions:

I wonder why the author did not use an Interface to represent the abstract type FileSystemElement? Isn't using an interface for this type correct?

You are correct, an interface could have been used. However, it is not the best choice. As you know, an Interface does not allow you to add implementation code to its methods. You better use a class instead of an interface because you can include implementation details of the methods you see common between the sub-classes. In this case, you may want to share the validation of the name property for example.

As we know, files and directories must have names with similar constraint (e.g. maximum length of 256 characters). Therefore, it would be nice if I model this in the FileSystemElement. But an interface cannot have a abstract attribute, so I have to repeat name attribute in both Directory and File classes. Is there any better workaround for this problem?

In c# you could define zero, one or more properties as part of an interface, for example:

public interface IFileSysElement
{
    // Property declaration:
    string ElementName
    {
        get;
        set;
    }
...
}

So it is not a problem really.

The issue I see with the book's model is that having an association between a class and a sub class is cumbersome (to me). Another point to consider is the fact that the FileSystemElement name is the relative name (e.g. myFile.txt). You need another property or method to construct or retrieve the full file name for (e.g. C:\Temp\myFile.txt). This is the 'business identifier' for either classes.

NoChance
  • 12,412
  • 1
  • 22
  • 39
0

It is called the Composite Pattern and as such does not possess an Association between the Composite (Directory) and the Leaf (File). I think that was a diagramming mishap in the first picture, although technically it does not suggest an assocation between them two - it just looks like one.

panny
  • 317
  • 1
  • 2
  • 8
  • The leaf is FileSystemElement not File - you can have directories within directories. You could add a 'files' and a 'sub-directories' association which are derived subsets of the the unnamed association given, but it's not essential and there's no reason to believe having the target of the composition as the base class is a 'mishap'. – Pete Kirkham Feb 10 '13 at 21:48
-1

The base class approach makes sense because of the problem you raised in your second question. A base class allows you to have such an attribute and don't repeat yourself on validity checks etc.

On the other hand your interface approach makes sense because it offers you more flexibility. Suppose you want to add a third type of FileSystemElement that does not have a name attribute. And maybe this third type lends itself to use a very different base class. But you still want to address all three types from the Directory class. You can't do that with a base class.

So, let's see if we can combine the features. The motto here is separation of concerns.

  1. concern: address all elements of a filesystem in the same way.
  2. concern: Share the name implementation between the Directory and the File class.

We can't do both with one technique but nothing stops us from using both at the same time! Let's make FileSystemElement an interface and let Directory and File implement it. Additionally create a base class (possibly an abstract one) called e.g. NamedFileSystemElement with the desired attribute. Now let Directory and File inherit from NamedFileSystemElement. See, best of both worlds.

scarfridge
  • 1,796
  • 13
  • 20
  • -1 : This is very complicated without any real benefits. What would be that third item that doesn't have a name in a file system ? I can't think of any off the top of my head. The motto is also : You ain't gonna need it. So don't try to think about future-proofing your solution. Because the future unlikely will be as you predicted it. – marco-fiset Apr 27 '12 at 19:04
  • @marcof Maybe I should have made it more clearly that my answer is more concerned with a general composite pattern and the filesystem is just an example. I cannot think of any third FileSystemElement descendant either. But if you are designing classes for filesystems they are pretty likely to end up in a library and then you really want to separate your implementation from your interface. You cannot do that after releasing the lib. You find this approach often in real libs e.g. AbstractTableModel in Swing. If the OP is only about a non-lib filesystem model, go ahead, cut out the interface. – scarfridge Apr 28 '12 at 08:25