Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow access to but prevent instantiation of a nested class by external classes

I'm looking to define a nested class that is accessible to the container class and external classes, but I want to control instantiation of the nested class, such that only instances of the container class can create new instances of the nested class.

The proceeding code should hopefully demonstrate this:

public class Container
{
    public class Nested
    {
        public Nested() { }
    }

    public Nested CreateNested()
    {
        return new Nested();  // Allow
    }
}

class External
{
    static void Main(string[] args)
    {
        Container containerObj = new Container();
        Container.Nested nestedObj;

        nestedObj = new Container.Nested();       // Prevent
        nestedObj = containerObj.CreateNested();  // Allow

    }
}

Nested must be public in order for it to be accessible by External. I tried making the constructor for Nested protected, however that prevents Container from creating instances, as Container isn't a base class of Nested. I could set the constructor for Nested to internal, but I'm looking to prevent access to the constructor by all external classes, including those in the same assembly. Is there a way to do this?

If this cannot be achieved through access modifiers, I wonder if I could throw an exception within Nested(). However, I don't know how to test for the context within which new Nested() is called.

like image 875
Dan Stevens Avatar asked Oct 19 '12 13:10

Dan Stevens


People also ask

Does class nestedclass exist independently of class outerclass?

Thus in above example, class NestedClass does not exist independently of class OuterClass. A nested class has access to the members, including private members, of the class in which it is nested. However, the reverse is not true i.e., the enclosing class does not have access to the members of the nested class.

Are inner classes automatically instantiated with outer classes in Java?

No inner class objects are automatically instantiated with an outer class object. The outer class can call even the private methods of the inner class. The inner class object must be associated with an instance of the outer class. Nested classes that are declared static are just called static nested classes.

What are the advantages of nested classes in Java?

They enable you to logically group classes that are only used in one place, thus this increases the use of encapsulation, and creates more readable and maintainable code. The scope of a nested class is bounded by the scope of its enclosing class. Thus in above example, class NestedClass does not exist independently of class OuterClass.

Does the enclosing class have access to the members of nested class?

However, the reverse is not true i.e., the enclosing class does not have access to the members of the nested class. A nested class is also a member of its enclosing class.


2 Answers

How about abstraction via an interface?

public class Container
{
    public interface INested
    {
        /* members here */
    }
    private class Nested : INested
    {
        public Nested() { }
    }

    public INested CreateNested()
    {
        return new Nested();  // Allow
    }
}

class External
{
    static void Main(string[] args)
    {
        Container containerObj = new Container();
        Container.INested nestedObj;

        nestedObj = new Container.Nested();       // Prevent
        nestedObj = containerObj.CreateNested();  // Allow

    }
}

You can also do the same thing with an abstract base-class:

public class Container
{
    public abstract class Nested { }
    private class NestedImpl : Nested { }
    public Nested CreateNested()
    {
        return new NestedImpl();  // Allow
    }
}

class External
{
    static void Main(string[] args)
    {
        Container containerObj = new Container();
        Container.Nested nestedObj;

        nestedObj = new Container.Nested();       // Prevent
        nestedObj = containerObj.CreateNested();  // Allow

    }
}
like image 165
Marc Gravell Avatar answered Oct 25 '22 02:10

Marc Gravell


It is impossible to declare class in such way. I think that the best way for you would be to declare class as private and expose it through public interface:

class Program
{
    static void Main(string[] args)
    {
       // new S.N(); does not work
        var n = new S().Create();
    }
}

class S
{
    public interface IN
    {
        int MyProperty { get; set; }
    }
    class N : IN
    {
        public int MyProperty { get; set; }
        public N()
        {

        }
    }

    public IN Create()
    {
        return new N();
    }
}
like image 25
Rafal Avatar answered Oct 25 '22 00:10

Rafal