0

I have a group of classes (let's say B,C,D,E) that basically represent specific operations a user can execute. I would like to have a single point of access for creating these object and launch their executions.

My first idea to accomplish that is to create another class (let's say class A) which will hide the complexity of creating the operation object and will call the related execution methods.

The classes B,C,D,E will implements a common interface in order to simplify the call of the specific operation.

My concern is how to prevent the possibility, by other classes, to create and directly use instances of classes B,C,D,E. I thought to define them as nested classes for class A: but this would affect the possibility to easily add more operations without touching the source file of class A.

In my implementation A is a Singleton.

How can I restrict the visibility of a group of classes only to a single class?

Edit: The application has to be written in C++

Akinn
  • 109
  • 3
  • 2
    Which programming language do you use? Java would support this using modules introduced in Java 9. –  Aug 30 '19 at 09:12
  • I was looking for a language indipendent pattern, but I have to design it in c++ (and I am a beginner with it) – Akinn Aug 30 '19 at 09:29
  • 1
    Since Java did not support this kind of control over readability until the Java Module System was introduced in Java 9, it is hard to imagine a language independent pattern. I am not a C++ programmer and have no knowledge about how visibility is controlled by it. –  Aug 30 '19 at 09:35
  • I'll add the C++ as part of the question – Akinn Aug 30 '19 at 09:47
  • Do you want just to make it unlikely to create instances from B,C,D,E by accident (for someone who has still access to the source code and could change the code at any time), or are you after a mechanism to deploy A,B,C,D,E as part of a precompiled library, where only A is part of the public interface of that lib? Please clarify. – Doc Brown Aug 30 '19 at 11:26
  • It is considered rude to edit your question in such a way that it invalidates existing answers. Not only is it a complete waste of the answerer's time, it also makes them look stupid and incompetent, since it appears that they are answering the wrong question. It may also lead to answers being downvoted for not answering the question. Please, consider rolling back your edit. – Jörg W Mittag Aug 30 '19 at 11:38
  • That's why I have added a comment indicating I was about to update the question. Moreover, as I specified, I've initially though to a language indipendent solution, in order to learn more than a specific implementation; since people let me noticed this isn't possible, I have updated the question. I don't believe anyone think you gave a wrong answer because of the edit. Peace. – Akinn Aug 30 '19 at 11:53
  • @DocBrown I want to avoid that other developers could think to change the way to access them. – Akinn Aug 30 '19 at 11:54
  • will anyone outside A have to know about B, C, D, E, i.e. will you return them as value ? or as reference or pointers the members of which being accessed outside A B C D E ? – Christophe Aug 30 '19 at 11:59
  • @Christophe I would handle everything through A, so B,C,D,E will never be returned. The result of those classes will be totally managed in A. – Akinn Aug 30 '19 at 12:13
  • 2
    @AndreaGiordano ok, so it‘s a typical facade pattern ( https://medium.com/@andreaspoyias/design-patterns-a-quick-guide-to-facade-pattern-16e3d2f1bfb6 ) and the question is a “how can I ... in c++”. I’d then suggest to look on stackoverflow (e.g. https://stackoverflow.com/questions/20401372/library-design-hiding-dependencies ) . The easiest way is certainly not to include B..E headers, except in the cpp of A. If you are affraid of an accidental include, make the constructors of these classes protected and A a friend. – Christophe Aug 30 '19 at 12:38
  • 2
    @JörgWMittag: if I see a question where an answer would be pretty language dependent (with no programming language mentioned), I would hesitate to answer the question - chances are high that either the OP adds a language afterwards, or if not, the question gets closed as "too broad" ;-) – Doc Brown Aug 30 '19 at 12:56
  • 1
    ... and I think people should not be critized for trying to prevent their question getting closed. – Doc Brown Aug 30 '19 at 13:07

2 Answers2

1

I thought to define them as nested classes for class A: but this would affect the possibility to easily add more operations without touching the source file of class A.

If your problem is solely with not wanting to change the file (for what I presume are subversioning concerns), and you don't mind changing the class itself, then partial classes solve the issue for you.

This allows you to spread your parent class over multiple files, which in this case you can do to separate your parent class file from your nested class file(s).

/////////////////////////////// File: A.cs

partial ref class A
{
    // Things for A
};

/////////////////////////////// File: B.cs

partial ref class A
{
    class B
    {
        // Things for B
    }
};

/////////////////////////////// And so on...

Whether you group B,C,D,E in a single file or not is up to you. It depends on the size of the classes and how cohesive they are.

Flater
  • 44,596
  • 8
  • 88
  • 122
0

This can be solved in Ruby, for example, by making B, C, D, and E private constants of A:

class A
  class CommonInterface
    # whatever your common interface is
  end

  class B
    # do stuff
  end

  class C
    # do stuff
  end

  class D
    # do stuff
  end

  class E
    # do stuff
  end

  private_constant :CommonInterface, :B, :C, :D, :E
end

Or, by making B, C, D, and E instance variables of A:

class A
  common_interface = Class.new do
    # whatever your common interface is
  end

  @b = Class.new(common_interface) do
    # do stuff
  end

  @c = Class.new(common_interface) do
    # do stuff
  end

  @d = Class.new(common_interface) do
    # do stuff
  end

  @e = Class.new(common_interface) do
    # do stuff
  end
end

This is as good as it gets in the absence of reflection. (It is still possible to break encapsulation using reflective methods such as Object#instance_variable_get or Module#const_get.)

If you want to protect yourself against reflection, too, then you can use local variables and closures.

class A
  common_interface = Class.new do
    # whatever your common interface is
  end

  b = Class.new(common_interface) do
    # do stuff
  end

  c = Class.new(common_interface) do
    # do stuff
  end

  d = Class.new(common_interface) do
    # do stuff
  end

  e = Class.new(common_interface) do
    # do stuff
  end
end

In Newspeak and Scala, you could simply make the classes private.

Jörg W Mittag
  • 101,921
  • 24
  • 218
  • 318