oskarm
oskarm

Reputation: 153

OO Design - Exposing implementation details through an interface

I have a class, which holds some details in a large data structure, accepts an algorithm to perform some calculations on it, has methods to validate inputs to the data structure. But then I would like to return the data structure, so that it can be transformed into various output forms (string / C# DataTable / custom file output) by the View Model.

class MyProductsCollection {
    private IDictionary<string, IDictionary<int, ISet<Period>>> products;

    // ctors, verify input, add and run_algorithm methods
}

I know that you are supposed to use the "depend on interface not implementation" design principle, so I want to create an interface for the class.

How can I avoid writing the following interface? Reason being it would expose implementation details and bind any other concrete implementations to return the same form.

interface IProductsCollection {
    IDictionary<string, IDictionary<int, ISet<IPeriod>>> GetData();
    // other methods
}

How can I easily iterate over the data structure to form different varieties of outputs without bluntly exposing it like this?

EDIT:

Since the class takes in IFunc<IDictionary<string, IDictionary<int, ISet<IPeriod>>>> in the constructor to iterate over the data structure and perform calculations, I could supply it with another IFunc, which would construct the output instead of running calculations. However, I don't know how I could do this aside from the concrete class constructor.

Upvotes: 5

Views: 273

Answers (2)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726669

The structure of the IDictionary<string,IDictionary<int,ISet<Period>>> is very suspicious indeed - when you see a dictionary of dictionaries, good chances are that you have missed an opportunity or two to create a class to encapsulate the inner dictionary.

Without knowing much of the domain of your problem, I would suggest defining an interface to encapsulate the inner dictionary. It looks like something that associates a number to a set of periods, so you would define an interface like this:

interface IYearlyPeriods {
    bool HasPeriodsForYear(int year);
    ISet<Periond> GetPeriodsForYear(int year);
}

I have no idea what's in the periods, so you would need to choose a domain-specific name for the interface.

Moreover, you can wrap the next level of IDictionary too:

interface IProductDataSource {
    IEnumerable<string> ProductNames { get; }
    IYearlyPeriods GetProductData(string productName);
}

Now you can define an interface like this:

interface IProductsCollection {
    IProductDataSource GetDataSource();
    // other methods
}

The main idea is to use domain-specific interfaces in place of generic collections, so that the readers and implementers of your code would have some idea of what's inside without referring to the documentation.

You could go even further, and replace the IDictionary with the complex structure that you keep internally with an IDictionary of IProductPeriods implementation. If you would like to keep IYearlyPeriods that you expose to the users immutable, but would like to be able to make modifications yourself, you can make a mutable implementation, and keep it internal to the implementing class.

Upvotes: 2

Laoujin
Laoujin

Reputation: 10229

I would suggest to keep the IDictionary private and provide a simple IEnumerable in the interface.

In your case this could be a custom DTO that hides all the nastiness of the IDictionary<int, ISet<IPeriod>> - which is already quite complex and could (probably) easily change as you need to implement new features.

This could be something like:

class ExposedPeriod
{
      public int PeriodIdentifier { get; set; }
      public IEnumerable<IPeriod> Periods { get; set; }
}

The ExposedPeriod and PeriodIdentifier probably need better names though. Good names might be found in your domain vocabulary.

Upvotes: 0

Related Questions