8

I have a class A. This class contains two methods let say method1() and method2(). Now I have two other classes named B and C. Both classed will contain the same instance of A class.

Now I want to restrict access in such a way that my 'Bclass can only callmethod1()and my otherC' class can call method2(). The design scheme is as follow-

class A {
    void method1(){/*-------------*/}
    void method2(){/*-------------*/}
}

now if I create an instance of A and share it with my B and C class

class B {
    A ob;
    public B(A ob) {
        this.ob=ob;
    }
    public void process() {
        ob.method1(); //only call method1()
        ob.method2(); //can't access it.
    }
}

class C {
    A ob;
    public C(A ob) {
        this.ob=ob;
    }
    public void process() {
        ob.method2(); //only call method2()
        ob.method1(); //can't access it.
    }
}
Bilesh Ganguly
  • 3,792
  • 3
  • 36
  • 58
  • 1
    I am sorry, stack over flow is not allowing me to accept multiple answer. but really both answer are useful to me. So thanks to GhostCat and Shmosel. – Subhabrata Mondal Aug 03 '17 at 06:18

5 Answers5

10

Simple: you can't.

In contrast to the "friend" concept in C++, you can only change visibility for all other classes.

In other words: in Java, you are stuck with package protected, protected, private and public. No "private for B" and "public for C".

Of course, you could do very strange things, like a method analyzing its own stack trace, and throwing exceptions if it finds to be called by the "wrong" class. But doing so is most likely bad practice.

In that sense, the real answer is: step back and have a close look at the functionality behind those two methods. If you really think these functions need different visibility - then chances are that they should not be in the same class in the first place! Because they probably implement two very different responsibilities - and well, any class, method, ... should have exactly one single responsibility.

The closest you can get to is the suggestion by smosel: your class implements different interfaces, and you make sure that clients are using your class through the "interface" interface - then they are restricted in the methods they can call. But of course - a client can easily cast the interface reference into a class reference and call the other methods then.

Given the comments: alone the used names indicate the above point: when A is a ConfigurationLoader - why does it contain a method to check a configuration? A ConfigurationLoader should load the configuration (to be triggered by class C) - and the result of that operation would be a "configuration" object - and class B would then work with that configuration object (instead of interacting with the loader).

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 1
    Actually here class A is a Configuration Loader class which loads the configuration details, I have class B which is a factory class which will check the required configuration details present in the properties file. that functionality will done by method1(). But to read the actual content, i want to give privilege to class C which is a `APIConnector`. method2() will read the configuration details. So please suggest me how can i redesign it?? – Subhabrata Mondal Aug 02 '17 at 07:24
  • Ok i am refactoring my code as per your suggestion and @shamosel's suggestion. I am trying to combining both – Subhabrata Mondal Aug 02 '17 at 07:50
  • 1
    Thank you to both of you. what i have done, i am returning a configuration object which consists of both api configuration and basic configuration operation from my configuration file loader. Using two interfaces i have classified the operations related for api and basic, meaning here, `method1()` is for api configuration related operation and `method2()` is for basic operation. now within `B` class i am passing configuration object as basic configuration interface, so that my basic operations will be identical from api configuration operation. Same i did for class `C`. Thank you once again. – Subhabrata Mondal Aug 03 '17 at 06:13
7

One solution is to move each method into its own interface, and have A implement both interfaces:

interface A1 {
    void method1();
}

interface A2 {
    void method2();
}

class A implements A1, A2 {
    @Override public void method1() {}
    @Override public void method2() {}
}

Now you can pass the same object as A1 to B and as A2 to C. You may be able to cast it to A to access either method (depending on A's visibility), but that's unlikely to happen by mistake.

shmosel
  • 49,289
  • 6
  • 73
  • 138
  • That is a nice idea ;-) – GhostCat Aug 02 '17 at 07:36
  • Thank you to both of you. what i have done, i am returning a configuration object which consists of both api configuration and basic configuration operation from my configuration file loader. Using two interfaces i have classified the operations related for api and basic, meaning here, method1() is for api configuration related operation and method2() is for basic operation. now within B class i am passing configuration object as basic configuration interface, so that my basic operations will be identical from api configuration operation. Same i did for class C. Thank you once again. – Subhabrata Mondal Aug 03 '17 at 06:14
0

You should arrange your class hierarchy according to java access level rules which are specified at https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

For your needs, you might put method1 and method2 into different classes, say A1 and A2. Then A1 will be in same package with B, A2 will be in same package with C. Classes should be defined with no modifier.

yılmaz
  • 1,818
  • 13
  • 15
0

You can use 2 adapter classes and use a different one in a and b. Seems like a bit of an overkill to me. Another think you could do is create method 3 that calls method 1 or 2 and decide which one it calls on instantiation.

Jonathan Oron
  • 34
  • 1
  • 7
0

Technically there are several ways to do this, such as declaring your methods as private and then using reflection to invoke only the appropriate method from the class that is allowed to do that. However, this kind of design is in contrast with Java principles and using it is generally not a good idea. The best thing is to redesign the methods in order to achieve the desired result.

kernel_panic
  • 119
  • 11