Есть ли способ избежать приведения этого типа?

Рассмотрим следующий класс, который определяет и реализует интерфейс Foo:

public class MyClass {

    public Foo getFoo() {
        return new FooImpl();
    }

    public void fooMethod(Foo foo) {
        final fooImpl = (FooImpl) foo;
        fooImpl.hiddenMethod();
    }

    public interface Foo {
        void doSomething();
    }

    private class FooImpl implements Foo {
        public void doSomething();

        void hiddenMethod() {
        }
    }
}

Внешние классы вызовут MyClass.getFoo() для получения объекта Foo и могут передать его обратно в fooMethod(). fooMethod() ожидает FooImpl реализацию Foo и приводит Foo к FooImpl, чтобы он мог вызвать пакетный метод hiddenMethod().

Мой вопрос в том, что я не без ума от приведения Foo к FooImpl. Есть ли другой шаблон, который я могу использовать, чтобы сделать то же самое?

Заранее спасибо...


person Barry Fruitman    schedule 10.04.2014    source источник
comment
Заставьте свой fooMethod принять FooImpl.   -  person Sotirios Delimanolis    schedule 10.04.2014
comment
Почему Foo это interface? Обычно, когда вы пишете интерфейс, вы ожидаете, что, по крайней мере теоретически, может существовать более одного класса, реализующего его. Если вы пишете интерфейс и ожидаете, что будет только одна реализация, то у меня возникнет вопрос, почему вы пишете его как интерфейс. Может быть, есть веская причина. Но если вы объясните, в чем причина, возможно, мы сможем указать вам лучший способ организации кода. (P.S. Есть причины, по которым в C++ так делаются вещи, которые не применимы к Java.)   -  person ajb    schedule 10.04.2014


Ответы (3)


Проблема здесь в том, что вы неявно нарушаете принцип инкапсуляции. В вашем классе есть метод, который зависит от реализации и поэтому не является частью интерфейса Foo. Это нарушение принципов ООП, этот бросок — только верхушка айсберга. Что делать, если вы хотите разработать новый класс реализации Foo, который не имеет методов, которые вы хотите вызывать?

Вы должны перепроектировать свой код, чтобы вы могли добиться этого, вызывая только методы из интерфейса Foo.

person phil_20686    schedule 10.04.2014

Вы можете добавить метод hiddenMethod в интерфейс Foo

public interface Foo {
    ...   
    void hiddenMethod();
}

Поскольку интерфейс является контрактом для поддерживаемых операций, вам не нужно (не следует ли?) приводить объект к методам доступа за пределами интерфейса.

person Reimeus    schedule 10.04.2014

Вы должны опустить руки.

Делай таким образом

public void fooMethod(Foo foo) {
   if(foo instanceof FooImpl){
      final FooImpl fooImpl = (FooImpl) foo;
      fooImpl.hiddenMethod();
   }
}

Супертип не может быть приведен к понижению без явного приведения к понижению. Обязательно проверьте его перед приведением вниз с помощью оператора instanceof.


--РЕДАКТИРОВАТЬ--

Сделайте еще одну вещь, если хотите избежать кастинга. Также добавьте hiddenMethod() в интерфейс Foo.

public interface Foo {
    void doSomething();
    void hiddenMethod();
}
person Braj    schedule 10.04.2014