简体   繁体   中英

Java/Patterns for hiding methods from third party classes

I have a class A that has a series of handlers eg public void handleEv1(),public void handleEv2() etc. When an event occurs, another thread in class B, calls the correspondent handler from class A (class B has a reference to class A kind of observer-observable). In the handling of the event in the corresponding method of class A, A eventually raises an event to an eventListener (class C which is not created by me). My question is the following: is there a pattern I can use to "hide" the handling methods of class A from the classes that act as eventListeners (not implemented by me), and be "visible/accesible" only to class B (which I implement)?

I am editing my original question. I have class Csystem that has a lot of methods and the handlers I am talking about

public class Csystem()
{

   private AListener listener;//implements an event listener (the class C in my question)

//some methods here
 public void handleEventIncoming(Event e){
//Do some logic here
  listener.raiseEvent(e);
 }
 public void handleEventOutgoing(Event e); etc


}

CSystem is a class that is essentially an interface for other developers of other components to my code. Some other developer will write his own version of class AListener (class A) and use Csystem in his code. Whenever an event occurs somewhere (eg a message in the network arrived) class B will pass the event to the event handlers of CSystem

public class Dispatch{
//This is class B
 private CSystem s;

 private void event_occured(Event e)
 {
    s.handleEventIncoming(e);
 }
}   

} My problem is that both class Dispatch (implemented by me) and class AListener "see" the same interface of CSystem. I would like the developers who implement the AListener to see a different view of CSystem and "see" and be able to use only methods that are public. I don't think that it is a good idea to see methods someone actually can not use (handlers are meaningful to be used only by dispatcher) Is there a pattern to achieve this?

Thank you!

Use Interfaces. B's relationship with A is only via an Interface that B defines and A implements.

So from B's perspective, it doesn't even import A, or have access to the definition of A at compilation time.

Edited in response to question.

I beleive you have a class C

pre-existing, unchangable by you, code in some package xy;

Class CEvent {
   // some event definition
};

Class C {
    public void callWhenitHappens(CEvent theEvent) {
       // do something
    }
}

--- code you write ---

package p.q;
public Class A implements BEventInterface {

   public void bEventHappened( BEvent theBEvent ){
       // make a C event
       myC.callWhenitHappens(theCEvent);
   }

}

And your concern is that anybody , even including C could call that bEventHappened() method.

My feeling is that you're concerned by an unlikely problem. Why would someone go to the trouble of creating an A object and doing that? However there are some possibilities:

1). If A and B are in the same package, do not make A and it's method public. Only B needs to see them, so at package scope this will just work.

2). Anonymous inner class. Note here that A ia class with a no public methods, so C can't use it and yet B has public methods on the anonymous inner class it can use.

package p.q;

import p.q.B.BEvent;
import x.y.z.C.CEvent;
import x.y.z.C;

public class A  {

// anonymous class implementing required interface
private BListener myFacade = new BListener(){
    @Override
    public void listen(BEvent event) {
        bEventHappened(event);          
    }       
};

private B myB;
private C myC;

A() {
    myC = new C();
    myB = new B();
    myB.registerListener(myFacade);
}

private void bEventHappened( BEvent theBEvent ){
       myC.callWhenitHappens(myC.new CEvent() );
}
}

With classes B and C looking like:

package p.q;

public class B {

public class BEvent {
    public String what;
}

private BListener myListener;

private void fireEvent(){
    myListener.listen(new BEvent());
}

public void registerListener(BListener listener){
    myListener = listener;
}

}

and

package x.y.z;

public class C {
public class CEvent {
    public String what;
}

public void callWhenitHappens(CEvent event){
    //e3c
}

}

You appear to have a class with an interface with multiple responsibilities. This is a bad thing. A simple approach is to use anonymous inner classes to implement callback interfaces.

You can put A and B in package alpha and C in package omega. A and B have access to each other's package private members, but C does not. You should also use interfaces like djna said.

package alpha ;
public interface A { void doSomething ( ) ; }
public interface B { }
class AImpl implements A { ... void doSomethingPrivate ( ) { ... } }
class BImpl implements B { AImpl a ; ... a.doSomethingPrivate ( ) ; }

package omega ;
public interface C { public void handle ( alpha.a a ) ; ... }

You can do this like that:

interface EventSource<T>{ 
    void addEventListener(T listener);
    void removeEventListener(T listener);
}
class B implements EventSource<SomethingListener>
{
    A instA;
    ...
    public B(A instA)
    {
        this.instA = instA;
        instA.installEventSource(this);
        ...
    }
    ...
} 
class A
{
    ...
    public void installEventSource(EventSource source)
    {
        source.addEventListener(listener);
    }
    public void uninstallEventSource(EventSource source)
    {
        source.removeEventListener(listener);
    }
}

thank you for your example! I was not clear it seems. I have class Csystem that has a lot of methods and the handlers I am talking about

public class Csystem()
{

private AListener listener;//implements an event listener (the class C in my question)

//methods here
 public void handleEventIncoming(Event e){
//Do some logic here
  listener.raiseEvent(e);
 }
 public void handleEventOutgoing(Event e); etc


}

CSystem is a class that is essentially an interface for other developers of other components to my code. Some other developer will write his own version of class AListener (class A) and use Csystem in his code. Whenever an event occurs somewhere (eg a message in the network arrived) class B will pass the event to the event handlers of CSystem

public class Dispatch{
//This is class B
private CSystem s;

 private void event_occured(Event e)
 {
    s.handleEventIncoming(e);
 }
}   

}

My problem is that both class Dispatch (implemented by me) and class AListener "see" the same interface of CSystem. I would like the developers who implement the AListener to see a different view of CSystem and "see" and be able to use only methods that are public. I don't think that it is a good idea to see methods someone actually can not use (handlers are meaningful to be used only by dispatcher) Is there a pattern to achieve this?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM