Зачем вам объявлять интерфейс, а затем создавать экземпляр объекта с ним в Java?
Мы с другом изучаем Java. Сегодня мы смотрели интерфейсы, и мы немного обсудили, как используются интерфейсы.
Пример кода, показанного моим другом, содержал это:
IVehicle modeOfTransport1 = new Car();
IVehicle modeOfTransport2 = new Bike();
Где IVehicle - это интерфейс, который реализован как на автомобилях, так и на велосипедных классах.
При определении метода, который принимает значение IVehicle в качестве параметра, вы можете использовать методы интерфейса, а при запуске кода указанные выше объекты работают как обычно. Тем не менее, это прекрасно работает при объявлении автомобиля и велосипеда, как вам обычно хотелось бы:
Car modeOfTransport1 = new Car();
Bike modeOfTransport2 = new Bike();
Итак, мой вопрос: зачем вы использовали прежний метод над последним при объявлении и создании экземпляров объектов modeOfTransport? Это имеет значение?
Ответы
Ответ 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. Я все равно не знаю причины.