-1

We have different type of images, we store the image on disk in subfolders accordingly, and the metadata in database, including the fileTypeId. currently we have this:

public enum FileTypes
{
    Document=1,
    ProfileProto
    ...
}

and

switch (fileType)
   case 1:
        subdir = "documants"
   case 2:
        subdir = "profilephotos
   default: ...error...

something like this

This violates SOLID's open/close principle

So I tried to create this instead:

public class DocumentFileType : IFileType
{
    public int Id => 1;
    public string Subfolder => "documents";
}

but the issue is, when we store the metadata of the images into database, we store the id of the type into a database field. 1 or 2 in this case. So when I retreive I should do something like IFileType fileType = IFileType.instnceWithId(1) But this is not possible of course.

What could I do instead of this?

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
barii
  • 343
  • 1
  • 3
  • 12
  • 2
    I don't see the difference of storing a `FileTypes` and a `1`, given that they are, in the end, the same – Camilo Terevinto Mar 06 '18 at 10:07
  • you could use a factory pattern...but is this overkill for a file type...is there going to be another set of coders that need to use your code and extend it without having access to it? – Ctznkane525 Mar 06 '18 at 10:09
  • 1
    I think you found that C#'s `enum` isn't very Open/Closed. But your alternative actually looks worse. – H H Mar 06 '18 at 10:10
  • 2
    If your switch through your enum in a single place, then it's a bearable 'violation'. Otherwise, you introduce complexity for a little benefit. – Roman Gudkov Mar 06 '18 at 10:11
  • perhaps you are looking for this https://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/ – animalito maquina Mar 06 '18 at 10:23
  • Adding abstraction like `IFileType` would be a good solution if you would have some behavior(Object not Data Structure). Otherwise, sometimes it is not possible to avoid violation of some of the SOLID principles. Just separate code which might be changed in the future – OlegI Mar 06 '18 at 10:34

2 Answers2

0

I would stick to the simple solution with an Enum and use an Attribute to decorate it with the subdirectory string, to have all the needed data in one place:

public enum FileTypes
{
    [SubDirectory("documents")]
    Document = 1,

    [SubDirectory("profilefotos")]
    ProfileFoto = 2 
}
doerig
  • 1,857
  • 1
  • 18
  • 26
  • hmm, this is good, I like it. But I still need to change it (midify it) so it still violates Open/close, doesn't it? – barii Mar 06 '18 at 10:35
  • and it looks cimplex to retreive the value – barii Mar 06 '18 at 10:49
  • Yes, you need reflection to access the SubDirectory value (looks a bit ugly but is not really that complex). And to extend it with new Filetypes, you would still need to change the enum. With this aproach you can only eliminate the switch statement. – doerig Mar 06 '18 at 12:09
  • I have added another answer, but also keep the YAGNI principle in mind ;-) – doerig Mar 06 '18 at 12:20
  • with this, you need to register it, so you need to modify, again – barii Mar 06 '18 at 12:38
  • You always have to modify something if you extend the functionality. If you don't want to modify code, you could use a database table or config file to store the filetypes. – doerig Mar 06 '18 at 13:47
0

To make you code more extensible, I think you need some kind of registry that stores all known filetypes. The registry could be part of a library and exposed, so that external code could register their own filetypes.

public class DocumentFileTypeRegistry 
{
    IDictionary<int, IFileType> _registeredFileTypes = new Dictionary<int, IFileType>();

    public void RegisterType(IFileType type)
    {
        _registeredFileTypes[type.Id] = type;
    }

    public IFileType GetTypeById(int id)
    {
        return _registeredFileTypes[id];
    }
}

public class DocumentFileType : IFileType
{
    public int Id => 1;
    public string Subfolder => "documents";
}

public class PhotoFileType : IFileType
{
    public int Id => 2;
    public string Subfolder => "photos";
}

And then you have to register the Filetypes in your Registry:

_fileTypeRegistry = new DocumentFileTypeRegistry();
_fileTypeRegistry.RegisterType(new DocumentFileType());
_fileTypeRegistry.RegisterType(new PhotoFileType());

//retrieve the type by id
var fileType = _fileTypeRegistry.GetTypeById(1);
doerig
  • 1,857
  • 1
  • 18
  • 26