Rosdi Kasim
Rosdi Kasim

Reputation: 26006

Java, Cannot reduce the visibility of the inherited method from object

Continuing from this question: Why can't you reduce the visibility of a method in a Java subclass?

I need to create class B that is almost identical to class A, except that B cannot do certain things that A can.

Being a lazy programmer as I am, I tried to inherit A, only to greet with error that B cannot reduce the visibility of A methods. Duh!..

Now A is an API from a vendor, my intention is to encapsulate this API so that it is easier to use.

I wonder what is the best practice to work around this?

Upvotes: 14

Views: 19514

Answers (8)

Matthew Madson
Matthew Madson

Reputation: 1733

Another option you might consider.

Say you want to reduce the API of some class:

public class LargeApi {
  public void doFoo() { ... }
  public void doBar() { ... }
  public void doBaz() { ... }
  ...
  ...
}

Such that clients would only be exposed to say the doFoo method (or any method you'd prefer them to use instead):

public interface ReducedApi {
  void doFoo();
}

But in order for instances of the ReducedApi to be used anywhere the LargeApi is expected, you need a way to get back to the LargeApi (preferably without casting):

public interface ReducedApi {
  void doFoo();
  LargeApiClass asLargeApiClass();
}

An example implementation forcing clients to use your new reduced API might look like the following:

public class ReducedApiImpl 
  extends LargeApi 
  implements ReducedApi {

  // Don't let them instantiate directly, force them to use the factory method
  private ReducedApiImpl() {

  }

  // Notice, we're returning the ReducedApi interface
  public static ReducedApi newInstance() {
    return new ReducedApiImpl();
  }

  @Override
  public void doFoo() {
    super.doFoo();
  }

  @Override
  public LargeApi asLargeApi() {
    return this;
  }
}

Now your clients can use your reduced api for the common case, but cast back to the large api when needed:

ReducedApi instance = ReducedApiImpl.newInstance();
instance.doFoo();
callSomeMethodExpectingLargeApi(instance.asLargeApi());

Upvotes: 1

sinuhepop
sinuhepop

Reputation: 20326

If B can't do all thing A can, you couldn't treat B as an A.

Maybe you need a wrapper, not a subclasse.

EDIT:

So you'd understand you'll never reduce the "visibility" of a subclass method :). Throw an exception or do nothing is not reduce the visibility, therefore you need a wrapper. Sometimes, this situation is a signal of a bad design (only sometimes).

This is very related to circle-ellipse problem.

Upvotes: 3

rsp
rsp

Reputation: 23373

You can build a wrapper class offering a reduced API, or you can throw an exception like UnsupportedOperationException from the methods that you want to disable.

Upvotes: 2

willcodejavaforfood
willcodejavaforfood

Reputation: 44073

A facade is used when one wants an easier or simpler interface to work with.

You would have to create your own wrapper class (Facade Pattern) around your foreign interface.

interface Foreign
{
    void dontWantThis();
    void keepThis();
}

interface/class MyForeign
{
    void keepThis();
}

The implementation would then have a instance of Foreign that it can refer calls to.

Upvotes: 4

punkers
punkers

Reputation: 107

I would use the adapter pattern. http://en.wikipedia.org/wiki/Adapter_pattern

Upvotes: 0

Grodriguez
Grodriguez

Reputation: 21995

Two options:

If you need B to keep the same interface as A (so that client code can use any of the two without changes), you can override "forbidden" methods in B and have them throw an UnsupportedOperationException. For example:

public class A
{
    public int allowedMethod() { ... }
    public int forbiddenMethod() { ... }
}

public class B extends A
{
    public int forbiddenMethod()
    {
        throw new UnsupportedOperationException("Sorry, not allowed.");
    }
}

Or, if you really want the API of B to be a subset of the API of A, then just have B contain an instance of A, and delegate method calls appropriately.

    public class A
    {
        public int allowedMethod() { ... }
        public int forbiddenMethod() { ... }
    }

    public class B
    {
        private A a;

        public int allowedMethod()
        {
            return a.allowedMethod();
        }
    }

Upvotes: 18

William
William

Reputation: 13632

Use Composition rather than Inheritance.

i.e. class B holds a reference to a class A and internally calls methods on it.

Upvotes: 9

madhurtanwani
madhurtanwani

Reputation: 1219

The solution would probably use "composition" over "inhertence". You could have a property in class B, of type A. Then expose only those methods in B that you want to actually implement

Upvotes: 1

Related Questions