Click here to Skip to main content
Click here to Skip to main content

Friends and internal interface members at no cost with coding to interfaces

By , 18 Jun 2012
 

Preface

My coding experience shows that once a particular class has more than one public method, I start loosing control over the exact functionality of that particular class. So, I try to emphasize the interface of any class. The result is that almost all my classes, even the very internal ones have corresponding interfaces.

Programing to an interface is a way of coding. If you are there, you will easily adopt the ideas from this article. If you are not sure what programing to an interface means, I hope, you will fill the gap as soon as possible.

In other words: "Start program to an interface".

Introduction

In this article I will try to get a solution for two specific problems

  • Constructing objects from a predefined class only - aka friend access
  • Defining interface members with an internal access

But first - my understanding of the statements above.

Problem Statement

Constructing objects from a predefined class only

Let's code a transaction manager

interface ITransaction { }
class LoadingTransaction : ITransaction() { }
class TransactionManager
{
    ITransaction StartLoading()
    {
        return new LoadingTransaction();
    }
}

I would say that hiding the public constructor of the LoadingTransaction class suggests itself. The design above surely imposes that any transaction should be created by a transaction manager only.

Interface members with internal access

While the web is full of excellent answers to "Why interface can't have internal members", I still think that the question itself is a mix of two orthogonal concerns:

  • Who is allowed to implement a particular interface members
  • Who is allowed to use that particular interface member

Now consider the following member of an ILogger interface

interface ILogger
{
    ...
    void Reconfigure();
}

Any class that implements the ILogger interface is ought to implement the Reconfigure() method. No doubt here. But, what we may want is to restrict the initiators of a reconfiguration process - the callers of the Reconfigure() method.

Indeed, suppose the reconfiguration trigger is an internal detail of our assembly - then we want to express this fact explicitly in our design.

No one should call the Reconfigure() method from outside.

That what the internal access modifier on the Reconfigure() method should mean.

Implementation

Before I am ready to step into the promised implementation I need a way of total separation of an interface and its implementation.

Decoupling an Interface from a Specific Implementation

Given the transaction manager we started with, let's emit the ITransactionManager interface and its implementation as we did with the transaction itself.

interface ITransaction { }
class LoadingTransaction : ITransaction() { }
interface ITransactionManager 
{ 
    ITransaction StartLoading();
}
class TransactionManager : ITransactionManager
{
    ITransaction ITransactionManager.StartLoading()
    {
        return new LoadingTransaction();
    }
}

(See my article why I use explicit implementation)

I always struggle not to deal with any concrete implementations.

Let's hide the public constructors of both LoadingTransaction and TransactionManager classes

class LoadingTransaction : ITransaction() 
{
    public static ITransaction New()
    {
        return new LoadingTransaction();
    }
    
    private LoadingTransaction()
    { }
}
class TransactionManager : ITransactionManager() 
{
    public static ITransactionManager New()
    {
        return new TransactionManager();
    }
    
    private TransactionManager()
    { }
}

The New() method is a kind of a factory method that accomplishes the separation of an interface and its implementation. (The same may be achieved by using a dependency injector container)

From this point no one (especially later maintainers) do not deal with any concrete instances of our classes.

For instance, a little benefit from this way of coding

void main()
{
    var manager = TransactionManager.New();
    manager.StartLoading();     // good; still using ITransactionManager interface
}
Regardless of the usage of the var keyword the code above is not coupled to a concrete TransactionManager instance.

What is not true with a common coding practice

void main()
{
    var manager = new TransactionManager();
    manager.StartLoading();     // bad! coupled to a concrete TransactionManager implementation
}

The New() method is the crucial point of the friend access solution, so look at it once again carefully.

Now Comes the "Is My Friend Trick"

We are finally ready to express friend access explicitly
class LoadingTransaction : ITransaction() 
{
    public static ITransaction New(TransactionManager onlyAccess)
    {
        return new LoadingTransaction();
    }
    
    private LoadingTransaction()
    { }
}

Surprisingly we require a concrete instance of the TransactionManager class as a parameter of the LoadingTransaction.New() method call.

But the only one who has that concrete instance is the TransactionManager itself!

Take a brief and recall

class TransactionManager : ITransactionManager() 
{
    public static ITransactionManager New()
    {
        return new TransactionManager();
    }
    
    private TransactionManager()
    { }
}

The factory method New() returns an ITransactionManager interface. The constructor of the TransactionManager class is private and so inaccessible.

There is just no way to obtain a concrete instance of the TransactionManager class.

Indeed, the only one who can call the LoadingTransaction.New(TransactionManager onlyAccess) method is the TransactionManager itself or any of its descendant.

Internal members

It seems that the idea is clear: "Requiring a concrete instance of a class, while restricting the construction access of that class".

Now it is pretty easy to come up with this code

public class Internal
{
    internal Internal()
    { }
}

public interface ILogger
{
    ...
    void Reconfigure(Internal access);
}

We require a concrete instance of the Internal class as a parameter of the Reconfigure() method call. But that required instance may only be constructed within our assembly.

An Accomplishing Touch

There are two ways our friend accessed method might be compromised

class LoadingTransaction : ITransaction() 
{
    public static ITransaction New(TransactionManager onlyAccess)
    { }
}

Accessing the friend method with a null reference

void main()
{
    var transaction = LoadingTransaction.New(null);
}

What may be solved by just a run-time validation

class LoadingTransaction : ITransaction() 
{
    public static ITransaction New(TransactionManager onlyAccess)
    {
        if (onlyAccess == null)
            throw new AccessViolationException();
    }
}

The second flaw is accessing a friend method by casting to a concrete instance

void main()
{
    ITransactionManager manager = TransactionManager.New();
    var transaction = LoadingTransaction((TransactionManager) manager);
}

The solution here is a little bit more complicated. But the idea is pretty much the same. We require a concrete instance of a nested FriendsOnly class, while hiding its constructor.

class LoadingTransaction : ITransaction
{
    public static ITransaction New(TransactionManager.FriendsOnly access)
    { }
}
class TransactionManager
{
    private static FriendsOnly _meIsFriend;

    public class FriendsOnly
    {
        public static void GrantAccessPermissions() { _meIsFriend = new FriendsOnly(); }
        private FriendsOnly() { }
    }

    static TransactionManager()
    {
        FriendsOnly.GrantAccessPermissions();
    }

    public ITransaction StartLoading()
    {
        var transaction = LoadingTransaction.New(_meIsFriend);
        ...
    }
}
However, I would simply ignore the second flaw, since casting to a concrete class is already a dirty thing to do.

Conclusion

The accessibility obstacle may be handled by nested classes as well. However, the method represented by this article is superior in my opinion. It does not compromise the design nor the coding style.

Once you adopt the practice of programming to interfaces, you get the friend access for almost no charge.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mamasha Knows
Chief Technology Officer Cpp2Mtl Integration Solutions
United States United States
Member
My real name is Reuven Bass. My first article here was published under the Mamasha Knows pseudonym. It worked. So, I stay with Mamasha for a while. (If it works - do not touch it)
 
Programming became my life from thirteen. I love coding. I love beauty. I always try to combine coding and beauty.
 
RB

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 3, low coupling means low cohesion.memberNicolas Dorier29 Jun '12 - 20:32 
Using interface on every type is a nightmare to maintain, and I wish no developer to be ever tempted to do that because I don't want to be the one fixing their code and leaking abstraction later on.
 
I prefer developers that don't know what an interface is than ones that abuse the concept and try to use low coupling when they need high cohesion.
 
I worked on both type of project, the latter I was depressed and the former I was suicidal...
 
Better, I prefer developers that can take advantage of interface to extend or complete real use case functionality of their API.
 
Quote:
However, I would simply ignore the second flaw, since casting to a concrete class is already a dirty thing to do.

I agree on that, and the best solution is to instanciate concrete class directly.
 
If for a reason or another you need to use your transaction manager, use the concrete transaction manager with an explicit implementation of the interface ITransactionManager and a method (StartLoading) overload that return the concrete Transaction class...
 
When I see interface everywhere I imagine that the architect is telling me "I don't know what will change in the futur, so let's make everything possible".
This is forgetting that a software is not a building and can be modified if our initial guess was wrong or has changed with time.
 
The underlying problem is a requirement gathering, or domain knowledge problem.
The cure is talking with the actors about their expectation... I insist on talking.
 
Things that change together need to be kept together and without interface. (High cohesion)
 
Things that change appart should be kept appart and use interface to protect against change. (low coupling)
 
This two concepts between two package/namespace/class are mutually exclusive, and it is the work of the developers to understand the business problem and use the right balance.
 
For the wealth of our debugger and our mental health, I voted only 3 and hope you will not decide any developer to use an interface-only approach. This is really dangerous.
 
Sorry to be a bit aggressive on that I already lost too much hair because of this problem.
 
Nicolas,
GeneralRe: My vote of 3, low coupling means low cohesion.memberReuven Bass2 Jul '12 - 11:06 
A vast of experience and a lot of frustration. Thanks for the comment.
 
I will mention only, that I never said developers should use interfaces with every class. I said that I use interfaces for almost every class. But not for decoupling. My experience demands that. A half year later I will recall at a glance the exact external API of my class.
GeneralMy vote of 5memberPaulLinton20 Jun '12 - 13:15 
Clean, simple way to express the 'friend' concept.
Do you have any thoughts on how my domain model could make parameterless constructors available only to the Entity Framework implementation of my repository?
GeneralRe: My vote of 5memberReuven Bass21 Jun '12 - 6:15 
I would try to use a factory method when registering an interface. I don't familiar with entity but given a registration method
class Entity
{
    void Register<T>(T instance);
}
I would search for something like this
class Entity
{
    void Register<T>(Func<T> factoryMethod);
}
Than given my class
interface IClass { }
 
class AClass IClass
{
    public static IClass New() { return new AClass(); }
    private AClass { }
}
I will register it like this
void main()
{
    var entity = new Entity();
    entiry.Register<IClass>(() => AClass.New());
}

QuestionHow to solve the flaw and why?mvpPaulo Zemek19 Jun '12 - 5:06 
First, I must say that it is possible to solve the "is my friend flaw".
If instead of using the direct class (that can be cast) you use another class, that is internal and may only be created by the expected class...
 
But then, why not simple use the internal modifier on constructor?
In fact, why use everything as interface when the class may need a real relation?
For example: You needed to create a New method to avoid getting the class directly... but callers still neet to know the class to call the New static method.
I really consider interfaces fantastic when:
A) There may be more than one implementation of the code;
B) When the idea is to make some unit-tests they may avoid real-processing, by using an interfaced test-implementation instead.
C) When you really want to avoid direct references between classes.
 
But making a static call to New keeps a direct reference to the class. And classes they were meant to work together should not each one directly. The best example I can think at the moment are the IDbCommand, IDbConnection and others. Implementors (like SqlConnection) are fully typed, but with the interface you may work with any implementation without knowing the type. If you use a factory, you may very well use everything as interface. If not, you may gain the speed advantage of avoiding virtual calls.
AnswerRe: How to solve the flaw and why?memberReuven Bass19 Jun '12 - 9:43 
I agree that it is still coupled. But coupling to a static method is better that to a specific instance. The New() method is really a factory method that can be easily moved to a dedicated factory or dependency container.
 
Regarding internal constructor, it helps only in different assembly. My point is hiding construction in a same assembly (later maintainers should not create objects by their own will)
QuestionFirstmemberycg16691119 Jun '12 - 0:14 
Very good! It's important for me!
AnswerRe: FirstmemberReuven Bass19 Jun '12 - 10:31 
thanks

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 18 Jun 2012
Article Copyright 2012 by Mamasha Knows
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid