Grokys
Grokys

Reputation: 16526

Making a class available only to a single other class

I have a C# project in which I use the Memento/Command pattern to implement Undo/Redo functionality. The application is a WPF application that uses StructureMap for IOC, has extensive unit tests and makes use of mocking via interfaces using RhinoMocks.

In my code I have an Operation class which represents all undoable operations, and I also have an IRepositoryWriter interface through which all writes to the database are routed.

I am wondering what is the best way to enforce the policy that only Operation and its derived classes should be able to use IRepositoryWriter.

The obvious way to achieve this would be to make IRepositoryWriter a protected, nested interface of Operation.

Advantages: only Operation and derived classes have access to IRepositoryWriter.

Disadvantages: no longer can be used with StructureMap or Unit Tested.

What are some other solutions to this? The policy doesn't need to be strictly enforced - just enough to give a hint to someone else working on the codebase would be enough.

Upvotes: 2

Views: 207

Answers (5)

Ronald Wildenberg
Ronald Wildenberg

Reputation: 32094

You could divide your application into multiple libraries like this:

Lib1
    UI code
Lib2
    Operation and derived classes
Lib3
    IRepositoryWriter and implementation

Only Lib2 should have a reference to Lib3. You could even use the InternalsVisibleToAttribute to ensure that internal components of Lib3 are only visible to Lib2 and make IRepositoryWriter and implementation(s) internal.

This way you can still have all the unit tests you want. Of course there is nothing that prevents another developer from creating a reference from Lib1 to Lib3 but that's a lot easier to enforce.

Upvotes: 2

Mark Mullin
Mark Mullin

Reputation: 1340

The internal keyword restricts access to a class to elements within a single assembly, i.e. an internal class isn't visible outside of the assembly - put Operation, Operation subclasses, and IRepositoryWriter into a single assembly by themselves

Upvotes: 0

Doobi
Doobi

Reputation: 4842

What about replacing IRepositoryWriter with an RepositoryWriter with a constructor that takes the Operation as a parameter?

Upvotes: 1

Nobody
Nobody

Reputation: 4841

Probably overkill in this case but if you absoloutely must adhere to the DRY principle, you could write some script to alter only the .cs files that need the interface - the script could read a file that is just a list of classes that are allowed to implement the interface. That way you can nest the interface in each class that uses it, including unit tests without any duplication of knowledge. Of course the downside is that youre introducing a whole new level of complexity.

In hindsight, probably would do more harm than good, given that you can just add a comment to warn other devs of what you're doing but at least its a different perspective on the problem for you.

Upvotes: 0

Jamiec
Jamiec

Reputation: 136074

The policy doesn't need to be strictly enforced - just enough to give a hint to someone else working on the codebase would be enough

/// <summary>
///    blah blah, what this interface is for
/// </summary>
/// <remarks>
///   This interface should only be implemented by inheritors of Operation.
/// </remarks>
public interface IRepositoryWriter{}

Just stating the obvious solution for you. ;)

Upvotes: 1

Related Questions