Подтвердить что ты не робот

Зачем вам объявлять интерфейс, а затем создавать экземпляр объекта с ним в Java?

Мы с другом изучаем Java. Сегодня мы смотрели интерфейсы, и мы немного обсудили, как используются интерфейсы.

Пример кода, показанного моим другом, содержал это:

IVehicle modeOfTransport1 = new Car();
IVehicle modeOfTransport2 = new Bike();

Где IVehicle - это интерфейс, который реализован как на автомобилях, так и на велосипедных классах. При определении метода, который принимает значение IVehicle в качестве параметра, вы можете использовать методы интерфейса, а при запуске кода указанные выше объекты работают как обычно. Тем не менее, это прекрасно работает при объявлении автомобиля и велосипеда, как вам обычно хотелось бы:

Car modeOfTransport1 = new Car();
Bike modeOfTransport2 = new Bike();

Итак, мой вопрос: зачем вы использовали прежний метод над последним при объявлении и создании экземпляров объектов modeOfTransport? Это имеет значение?

4b9b3361

Ответ 1

Здесь неважно.

Там, где это действительно имеет значение, это другие интерфейсы, которые должны работать на IVehicle. Если они принимают параметры и возвращают значения как IVehicle, тогда код будет более легко расширяемым.

Как вы отметили, любой из этих объектов может быть передан методу, который принимает параметр IVehicle в качестве параметра.

Если у вас был следующий код, в котором использовались конкретные операции с Car или Bike, тогда было бы выгодно объявить их как автомобиль или велосипед. Специальные операции на автомобиле и велосипеде будут доступны для каждого из соответствующих объектов, и оба они могут использоваться (то есть могут быть переданы) как IVehicle.

Ответ 2

Существует большой плюс при объявлении их с использованием интерфейса, который называется "кодированием интерфейса" вместо "кодирования для реализации", который является большим принцип объектно-ориентированного дизайна (OOD), таким образом вы можете объявить метод следующим образом:

public void (IVehicle myVehicle)

и он примет любой объект, реализующий этот интерфейс, а затем во время выполнения он будет вызывать реализацию следующим образом:

public void (IVehicle myVehicle)
{
    myVehicle.run() //This calls the implementation for that particular vehicle.
}

Чтобы ответить на исходный вопрос, почему вы используете один над другим, есть несколько причин:

1) Объявление их с помощью интерфейса означает, что позднее вы можете заменить это значение на любой другой конкретный класс, который реализует этот интерфейс, вместо того, чтобы быть заблокированным в конкретном конкретном классе

2) Вы можете в полной мере воспользоваться полиморфизмом, объявив их с помощью интерфейса, потому что каждая реализация может вызывать правильный метод во время выполнения.

3) Вы следуете принципу OOD кода в интерфейс

Ответ 3

Вы действительно спрашиваете: какой ссылочный тип я должен использовать?

Как правило, вы хотите использовать как можно более общий ссылочный тип, который по-прежнему дает вам доступ к поведению, которое вам нужно. Это означает любой из интерфейсов или родительских классов вашего конкретного типа, а не сам конкретный тип. Конечно, не заходите слишком далеко - например, вы, конечно, не хотите объявлять все как Object!

Рассмотрим следующие параметры:

Set<String> values1 = new TreeSet<String>();
TreeSet<String> values2 = new TreeSet<String>();
SortedSet<String> values3 = new TreeSet<String>();

Все три действительны, но, как правило, первая опция values1 лучше, потому что вы сможете получить доступ только к поведению интерфейса Set, поэтому позже вы можете легко выполнить замену в другой реализации:

Set<String> values1 = new HashSet<String>();

Остерегайтесь использования второго варианта values2. Он позволяет использовать конкретное поведение реализации TreeSet таким образом, чтобы сменять место в другой реализации Set стало сложнее. Это прекрасно, пока ваша цель. Таким образом, в вашем примере используйте ссылку Car или Bike только тогда, когда вам нужен доступ к чему-то, что не находится в интерфейсе IVehicle. Имейте в виду, что следующее не будет работать:

TreeSet<String> values2 = new HashSet<String>(); // does not compile!

Тем не менее, есть моменты, когда вам нужен доступ к методам, которые относятся к самому общему типу. Это показано в третьем варианте values3 - ссылка более конкретна, чем Set, что позволяет вам позже полагаться на поведение SortedSet.

TreeSet<String> values3 = new ConcurrentSkipListSet<String>();

Вопрос о ссылочных типах применяется не только там, где объявляются переменные, но также и в методах, где вы должны указывать тип каждого параметра. К счастью, правило "использовать как общий ссылочный тип" возможно также применяется к параметрам метода.

Ответ 4

Честно говоря, ваш спор довольно спорный. Здесь происходит неявное преобразование в IVehicle. Вы и ваш друг, по-видимому, спорите о том, лучше ли это делать сразу (согласно первому списку кода) или позже (когда вы вызываете метод в соответствии со вторым списком кодов). В любом случае, он будет неявно преобразован в IVehicle, поэтому реальный вопрос - вам нужно иметь дело с Автомобилем или просто с Автомобилем? Если все, что вам нужно, это IVehicle, первый способ - это прекрасно (и предпочтительнее, если позже вы хотите прозрачно поменять автомобиль на велосипеде). Если вам нужно рассматривать его как автомобиль в других точках вашего кода, просто оставьте его как автомобиль.

Ответ 5

Потому что вам все равно, что такое реализация... только то, что это такое.

Скажите, что у вас есть животное

interface Animal {
    String speak();
}

class Cat implements Animal {

    void claw(Furniture f) { /* code here */ }

    public String speak() { return "Meow!" }
}

class Dog implements Animal {

    void water(FireHydrant fh) { /* code here */ }

    public String speak() { return "Woof!"; }
}

Теперь вы хотите дать своему ребенку домашнее животное.

Animal pet = new ...?
kid.give(pet);

И вы вернетесь позже

Animal pet = kid.getAnimal();

Вы не хотите идти

pet.claw(favorateChair);

Потому что вы не знаете, имел ли ребенок собаку или нет. И тебе все равно. Вы только знаете, что - Анималы - могут говорить. Вы ничего не знаете об их взаимодействии с мебелью или пожарными гидрантами. Вы знаете, что животные говорят. И это заставляет вашу дочь хихикать (или нет!)

kid.react(pet.speak());

С этим, когда вы делаете золотую рыбу, реакция ребенка довольно хромает (получается, что золотые рыбки не говорят!) Но когда вы положите медведя, реакция довольно страшная!

И вы не могли бы этого сделать, если бы сказали

Cat cat = new Cat();

потому что вы ограничиваете себя способностями Cat.

Ответ 6

Программа для интерфейса, а не для реализации.

Когда вы программируете на интерфейс, вы будете писать код, который может обрабатывать любой вид транспортного средства. Поэтому в будущем ваш код без изменений должен работать с Trains и Planes.

Если вы проигнорируете интерфейс, вы застряли в CArs и Bikes, и для любых новых автомобилей потребуются дополнительные модификации кода.

Принцип:

Открыть для расширения, закрыто для модификации.

Ответ 7

Объявление интерфейсов и их создание с помощью объектов позволяет использовать мощную концепцию polymorphism.

List<IVehicle> list = new ArrayList<IVehicle>();
list.add(new Car());
list.add(new Bike());

for (int i = 0; i < list.size(); ++i)
    list.get(i).doSomeVehicleAction();   // declared in IVehicle and implemented differently in Car and Bike

Чтобы явным образом ответить на вопрос: вы бы использовали объявление интерфейса (даже если знаете конкретный тип), чтобы вы могли передавать несколько типов (которые реализуют один и тот же интерфейс) методу или коллекции; то поведение, обычное для каждого типа реализации, может быть вызвано независимо от того, что является фактическим типом.

Ответ 8

интерфейсы скважин - это поведение, а классы - их реализация, поэтому будет несколько раз позже, когда вы будете программировать, где вы будете знать только поведение (интерфейс). и чтобы использовать его, вы будете реализовывать их, чтобы извлечь выгоду из этого. он в основном используется для скрытия деталей реализации от пользователя, только сообщая им о поведении (интерфейсе).

Ответ 9

Ваша интуиция правильная; тип переменной должен быть как можно более конкретным.

Это отличается от типов возвращаемых методов и типов параметров; дизайнеры API хотят быть немного абстрактными, поэтому API может быть более гибким.

Переменные не являются частью API. Это детали реализации. Абстракция обычно не применяется.

Ответ 10

С "Режим IVehicleOfTransport1 = новый автомобиль();", методы, принадлежащие только Авто, недоступны для режимаOfTransport1. Я все равно не знаю причины.