Полиморфизм против переопределения и перегрузки

Что касается Java, когда кто-то спрашивает:

что такое polymorphism?

Будет ли перегрузка или переопределение приемлемым ответом?

Я думаю, что это немного больше, чем это.

ЕСЛИ у вас есть абстрактный базовый class, который определил метод без реализации, и вы определили этот метод в подclassе, это все еще переопределяет?

Я думаю, что перегрузка – не правильный ответ.

Самый ясный способ выразить polymorphism – это абстрактный базовый class (или интерфейс)

public abstract class Human{ ... public abstract void goPee(); } 

Этот class является абстрактным, потому что метод goPee() не определен для людей. Он определен только для подclassов Мужской и Женский. Кроме того, человек является абстрактным понятием – вы не можете создать человека, который не является ни мужчиной, ни женщиной. Это должно быть одно или другое.

Поэтому мы откладываем реализацию с использованием абстрактного classа.

 public class Male extends Human{ ... @Override public void goPee(){ System.out.println("Stand Up"); } } 

а также

 public class Female extends Human{ ... @Override public void goPee(){ System.out.println("Sit Down"); } } 

Теперь мы можем рассказать всю комнату, полную Людей, чтобы пойти мочиться.

 public static void main(String[] args){ ArrayList group = new ArrayList(); group.add(new Male()); group.add(new Female()); // ... add more... // tell the class to take a pee break for (Human person : group) person.goPee(); } 

Выполнение этого приведет к:

 Stand Up Sit Down ... 

Полиморфизм – это способность экземпляра classа вести себя так, как если бы это был экземпляр другого classа в дереве наследования, чаще всего один из его classов-предков. Например, в Java все classы наследуют от Object. Поэтому вы можете создать переменную типа Object и присвоить ей экземпляр любого classа.

Переопределение – это тип функции, которая встречается в classе, который наследуется от другого classа. Функция переопределения «заменяет» функцию, унаследованную от базового classа, но делает это таким образом, что она вызывается даже тогда, когда экземпляр ее classа притворяется другим типом посредством polymorphismа. Ссылаясь на предыдущий пример, вы можете определить свой собственный class и переопределить функцию toString (). Поскольку эта функция наследуется от Object, она все равно будет доступна, если вы скопируете экземпляр этого classа в переменную Object-type. Обычно, если вы вызываете toString () в своем classе, пока он притворяется объектом, версия toString, которая будет фактически запускаться, является той, которая определена на самом объекте. Однако, поскольку функция является переопределением, определение toString () из вашего classа используется даже тогда, когда истинный тип экземпляра classа скрыт за polymorphismом.

Перегрузка – это действие определения нескольких методов с тем же именем, но с разными параметрами. Он не имеет отношения ни к переопределению, ни к polymorphismу.

Вот пример polymorphismа в псевдо-C # / Java:

 class Animal { abstract string MakeNoise (); } class Cat : Animal { string MakeNoise () { return "Meow"; } } class Dog : Animal { string MakeNoise () { return "Bark"; } } Main () { Animal animal = Zoo.GetAnimal (); Console.WriteLine (animal.MakeNoise ()); } 

Основная функция не знает тип животного и зависит от поведения конкретной реализации метода MakeNoise ().

Edit: Похоже, Брайан избил меня до удара. Смешно, мы использовали тот же пример. Но приведенный выше код должен помочь прояснить концепции.

Полиморфизм означает более чем одну форму, тот же объект выполняет различные операции в соответствии с требованием.

Полиморфизм может быть достигнут двумя способами:

  1. Метод переопределения
  2. Перегрузка метода

Метод перегрузки означает запись двух или более методов в одном classе с использованием того же имени метода, но параметры передачи отличаются.

Метод overriding означает, что мы используем имена методов в разных classах, то есть метод родительского classа используется в дочернем classе.

В Java для достижения polymorphismа ссылочная переменная суперclassа может содержать объект подclassа.

Для достижения polymorphismа каждый разработчик должен использовать те же имена методов в проекте.

Для достижения polymorphismа используются как переопределение, так и перегрузка.

У вас может быть метод в classе, который переопределяется в одном или нескольких подclassах. Метод выполняет разные действия в зависимости от того, какой class использовался для создания объекта.

  abstract class Beverage { boolean isAcceptableTemperature(); } class Coffee extends Beverage { boolean isAcceptableTemperature() { return temperature > 70; } } class Wine extends Beverage { boolean isAcceptableTemperature() { return temperature < 10; } } 

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

  class Server { public void pour (Coffee liquid) { new Cup().fillToTopWith(liquid); } public void pour (Wine liquid) { new WineGlass().fillHalfwayWith(liquid); } public void pour (Lemonade liquid, boolean ice) { Glass glass = new Glass(); if (ice) { glass.fillToTopWith(new Ice()); } glass.fillToTopWith(liquid); } } 

Вы правы, что перегрузка – это не ответ.

Ни то, ни другое. Переопределение – это способ, которым вы получаете polymorphism. Полиморфизм – это способность объекта изменять поведение, основанное на его типе. Это лучше всего продемонстрировать, когда вызывающий объект, который проявляет polymorphism, не знает, какой именно тип объекта является объектом.

Конкретно говоря, перегрузка или переопределение не дает полной картины. Полиморфизм – это просто способность объекта специализировать свое поведение на основе его типа.

Я бы не согласился с некоторыми из ответов здесь в том, что перегрузка – это форма polymorphismа (параметрический polymorphism) в случае, когда метод с одним и тем же именем может вести себя по-разному, давая разные типы параметров. Хорошим примером является перегрузка оператора. Вы можете определить «+», чтобы принимать разные типы параметров – например, строки или int – и на основе этих типов, «+» будет вести себя по-разному.

Полиморфизм также включает методы наследования и переопределения, хотя они могут быть абстрактными или виртуальными в базовом типе. Что касается polymorphismа на основе наследования, Java поддерживает только наследование одного classа, ограничивая его полиморфное поведение по отношению к одной цепочке базовых типов. Java поддерживает реализацию нескольких интерфейсов, что является еще одной формой полиморфного поведения.

Классический пример: собаки и кошки – животные, животные имеют метод makeNoise. Я могу выполнять итерацию по множеству животных, вызывающих makeNoise, и ожидать, что они сделают там соответствующую реализацию.

Вызывающий код не должен знать, каково конкретное животное.

То, что я считаю polymorphismом.

Полиморфизм – это способность объекта появляться в нескольких формах. Это предполагает использование наследования и виртуальных функций для построения семейства объектов, которые могут быть взаимозаменяемы. Базовый class содержит прототипы виртуальных функций, возможно, нереализованных или стандартных реализаций, которые диктует приложение, и различные производные classы каждый реализует их по-разному, чтобы влиять на разные поведения.

Ни:

Перегрузка – это когда у вас есть одно и то же имя функции, которое принимает разные параметры.

Переопределение – это когда дочерний class заменяет метод родителя одним из своих (это само по себе не является polymorphismом).

Полиморфизм является поздним связыванием, например, вызываются методы базового classа (родителя), но только до тех пор, пока среда выполнения не сообщит о том, что такое фактический объект, – это может быть дочерний class, методы которого различны. Это связано с тем, что любой дочерний class может использоваться там, где определяется базовый class.

В Java много polymorphismа вы видите в библиотеке коллекций:

 int countStuff(List stuff) { return stuff.size(); } 

Список является базовым classом, компилятор не имеет понятия, если вы считаете связанный список, вектор, массив или реализацию пользовательского списка, если он действует как List:

 List myStuff = new MyTotallyAwesomeList(); int result = countStuff(myStuff); 

Если вы перегрузили, у вас будет:

 int countStuff(LinkedList stuff) {...} int countStuff(ArrayList stuff) {...} int countStuff(MyTotallyAwesomeList stuff) {...} etc... 

и правильная версия countStuff () будет выбрана компилятором для соответствия параметрам.

Полиморфизм просто означает «многие формы».

Он не требует наследования для достижения … поскольку реализация интерфейса, которая не является наследованием вообще, служит полиморфным потребностям. Возможно, реализация интерфейса выполняет полиморфные потребности «Лучше», чем наследование.

Например, вы бы создали суперclass для описания всех вещей, которые могут летать? Я не думаю, что нет. Вам будет лучше всего создать интерфейс, описывающий полет и оставить его на этом.

Таким образом, поскольку интерфейсы описывают поведение, а имена методов описывают поведение (для программиста), не слишком далеко рассмотреть возможность перегрузки метода как меньшей формы polymorphismа.

Термин перегрузка относится к наличию нескольких версий чего-то с таким же именем, как правило, с разными списками параметров

 public int DoSomething(int objectId) { ... } public int DoSomething(string objectName) { ... } 

Таким образом, эти функции могут делать то же самое, но у вас есть возможность вызвать его с помощью идентификатора или имени. Не имеет ничего общего с наследованием, абстрактными classами и т. Д.

Переопределение обычно относится к polymorphismу, как вы описали в своем вопросе

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

Переопределяя, когда мы наследуем базовый class и делаем производный class, тогда, если в производном classе существует метод, который имеет то же имя, что и метод (одно имя, тот же аргумент, тот же тип возвращаемого значения), определяют в базовом classе, а затем его называют Overriding ..

  class Vehicle{ void run() { System.out.println("Vehicle is running"); } } class Bike2 extends Vehicle{ void run() { System.out.println("Bike is running safely"); } public static void main(String args[]){ Bike2 obj = new Bike2(); obj.run(); } 

Выход: Велосипед работает безопасно …….. Чтобы лучше понять переопределение, посетите: http://javabyroopam.blogspot.in/

Перегрузка Просто два метода, которые имеют одно и то же имя, но имеют другой список аргументов, называются перегрузками.

  class Calculation{ void sum(int a,int b){System.out.println(a+b);} void sum(int a,int b,int c){System.out.println(a+b+c);} public static void main(String args[]){ Calculation obj=new Calculation(); obj.sum(10,10,10); obj.sum(20,20); } } 

выход 30,20

что такое polymorphism?

Из учебника java

Словариское определение polymorphismа относится к принципу в биологии, в котором организм или вид могут иметь много разных форм или стадий. Этот принцип также может быть применен к объектно-ориентированному программированию и языкам, таким как язык Java. Подclassы classа могут определять свое собственное уникальное поведение и совместно использовать одни и те же функциональные возможности родительского classа.

Рассматривая примеры и определение, следует принять во внимание переопределение .

Что касается вашего второго запроса:

ЕСЛИ у вас есть абстрактный базовый class, который определил метод без реализации, и вы определили этот метод в подclassе, это все еще переопределяет?

Его следует назвать переопределяющим.

Взгляните на этот пример, чтобы понять различные типы переопределения.

  1. Базовый class не обеспечивает реализацию, а подclass должен переопределить полный метод – (аннотация)
  2. Базовый class обеспечивает реализацию по умолчанию, а подclass может изменять поведение
  3. super.methodName() добавляет расширение к реализации базового classа, вызывая super.methodName() как первый оператор
  4. Базовый class определяет структуру алгоритма (метод Template), а подclass будет переопределять часть алгоритма

fragment кода:

 import java.util.HashMap; abstract class Game implements Runnable{ protected boolean runGame = true; protected Player player1 = null; protected Player player2 = null; protected Player currentPlayer = null; public Game(){ player1 = new Player("Player 1"); player2 = new Player("Player 2"); currentPlayer = player1; initializeGame(); } /* Type 1: Let subclass define own implementation. Base class defines abstract method to force sub-classes to define implementation */ protected abstract void initializeGame(); /* Type 2: Sub-class can change the behaviour. If not, base class behaviour is applicable */ protected void logTimeBetweenMoves(Player player){ System.out.println("Base class: Move Duration: player.PlayerActTime - player.MoveShownTime"); } /* Type 3: Base class provides implementation. Sub-class can enhance base class implementation by calling super.methodName() in first line of the child class method and specific implementation later */ protected void logGameStatistics(){ System.out.println("Base class: logGameStatistics:"); } /* Type 4: Template method: Structure of base class can't be changed but sub-class can some part of behaviour */ protected void runGame() throws Exception{ System.out.println("Base class: Defining the flow for Game:"); while ( runGame) { /* 1. Set current player 2. Get Player Move */ validatePlayerMove(currentPlayer); logTimeBetweenMoves(currentPlayer); Thread.sleep(500); setNextPlayer(); } logGameStatistics(); } /* sub-part of the template method, which define child class behaviour */ protected abstract void validatePlayerMove(Player p); protected void setRunGame(boolean status){ this.runGame = status; } public void setCurrentPlayer(Player p){ this.currentPlayer = p; } public void setNextPlayer(){ if ( currentPlayer == player1) { currentPlayer = player2; }else{ currentPlayer = player1; } } public void run(){ try{ runGame(); }catch(Exception err){ err.printStackTrace(); } } } class Player{ String name; Player(String name){ this.name = name; } public String getName(){ return name; } } /* Concrete Game implementation */ class Chess extends Game{ public Chess(){ super(); } public void initializeGame(){ System.out.println("Child class: Initialized Chess game"); } protected void validatePlayerMove(Player p){ System.out.println("Child class: Validate Chess move:"+p.getName()); } protected void logGameStatistics(){ super.logGameStatistics(); System.out.println("Child class: Add Chess specific logGameStatistics:"); } } class TicTacToe extends Game{ public TicTacToe(){ super(); } public void initializeGame(){ System.out.println("Child class: Initialized TicTacToe game"); } protected void validatePlayerMove(Player p){ System.out.println("Child class: Validate TicTacToe move:"+p.getName()); } } public class Polymorphism{ public static void main(String args[]){ try{ Game game = new Chess(); Thread t1 = new Thread(game); t1.start(); Thread.sleep(1000); game.setRunGame(false); Thread.sleep(1000); game = new TicTacToe(); Thread t2 = new Thread(game); t2.start(); Thread.sleep(1000); game.setRunGame(false); }catch(Exception err){ err.printStackTrace(); } } } 

вывод:

 Child class: Initialized Chess game Base class: Defining the flow for Game: Child class: Validate Chess move:Player 1 Base class: Move Duration: player.PlayerActTime - player.MoveShownTime Child class: Validate Chess move:Player 2 Base class: Move Duration: player.PlayerActTime - player.MoveShownTime Base class: logGameStatistics: Child class: Add Chess specific logGameStatistics: Child class: Initialized TicTacToe game Base class: Defining the flow for Game: Child class: Validate TicTacToe move:Player 1 Base class: Move Duration: player.PlayerActTime - player.MoveShownTime Child class: Validate TicTacToe move:Player 2 Base class: Move Duration: player.PlayerActTime - player.MoveShownTime Base class: logGameStatistics: 

перегрузка – это когда вы определяете 2 метода с тем же именем, но с разными параметрами

переопределение – это то, где вы изменяете поведение базового classа с помощью функции с тем же именем в подclassе.

Таким образом, polymorphism связан с переопределением, но не с перегрузкой.

Однако если кто-то дал мне простой ответ «переопределения» на вопрос «Что такое polymorphism?» Я бы попросил дать дополнительные объяснения.

Полиморфизм более вероятен, поскольку это имеет значение … для ПЕРЕКРЫТИЯ в java

Речь идет о различном поведении объекта SAME в разных ситуациях (в программировании … вы можете называть разные АРГУМЕНТЫ)

Я думаю, что приведенный ниже пример поможет вам понять … Хотя это не PURE java-код …

  public void See(Friend) { System.out.println("Talk"); } 

Но если мы изменим АРГУМЕНТ … ПОВЕДЕНИЕ будет изменено …

  public void See(Enemy) { System.out.println("Run"); } 

Человек (здесь «Объект») тот же …

Полиморфизм – это множественные реализации объекта, или вы можете сказать несколько форм объекта. скажем, у вас есть class Animals как абстрактный базовый class, и у него есть метод под названием movement() который определяет способ перемещения животного. Теперь на самом деле у нас разные виды животных, и они движутся по-разному, а некоторые из них с двумя ногами, другие с 4, а некоторые без ног и т. Д. Чтобы определить различное movement() каждого животного на земле, нам нужно применить polymorphism. Однако вам нужно определить больше classов, т.е. class Dogs Cats Fish и т. Д. Затем вам нужно расширить эти classы из базового classа Animals и переопределить его movement() метода movement() с новой функциональностью движения, основанной на каждом животном, который у вас есть. Вы также можете использовать Interfaces для достижения этого. Ключевое слово здесь является переопределяющим, перегрузка отличается и не считается polymorphismом. с перегрузкой вы можете определить несколько методов «с тем же именем», но с разными параметрами на одном объекте или classе.

Я думаю, ребята, вы смешиваете понятия. Полиморфизм – это способность объекта вести себя по-разному во время выполнения. Для достижения этого вам понадобятся два реквизита:

  1. Поздняя привязка
  2. Наследование.

Сказав, что перегрузка означает что-то отличное от переопределения в зависимости от языка, который вы используете. Например, в Java не существует переопределения, но перегрузки . Перегруженные методы с различной сигнатурой в базовый class доступны в подclassе. В противном случае они будут переопределены (пожалуйста, посмотрите, что я имею в виду, что теперь нет способа вызвать метод базового classа вне объекта).

Однако в C ++ это не так. Любой перегруженный метод, независимо от того, является ли подпись одинаковой или нет (различная сумма, другой тип), также переопределяется . То есть на сегодняшний день метод базового classа больше не доступен в подclassе при вызове извне объекта подclassа, очевидно.

Поэтому ответ заключается в том, когда речь идет о перегрузке Java. На любом другом языке может быть иначе, как это происходит в c ++

Хотя, Полиморфизм уже подробно объяснен в этой статье, но я хотел бы сделать больше акцента на том, почему его часть.

Почему polymorphism настолько важен для любого языка ООП.

Попробуем создать простое приложение для телевизора с наследованием / polymorphismом и без него. Опубликуйте каждую версию приложения, мы делаем небольшую ретроспективу.

Предположим, вы являетесь разработчиком программного обеспечения в телевизионной компании, и вас попросят написать программное обеспечение для регуляторов громкости, яркости и цвета, чтобы увеличить и уменьшить их значения в команде пользователя.

Вы начинаете с написания classов для каждой из этих функций, добавляя

  1. set: – Установить значение controllerа. (Предположим, что это имеет специфический для controllerа код)
  2. get: – Получить значение controllerа. (Предположим, что у этого есть определенный код controllerа)
  3. adjust: – для проверки ввода и установки controllerа. (Общие проверки .. независимо от controllerов)
  4. сопоставление пользовательских входных данных с controllerами: – для получения пользовательского ввода и вызова controllerов соответственно.

Версия приложения 1

 import java.util.Scanner; class VolumeControllerV1 { private int value; int get() { return value; } void set(int value) { System.out.println("Old value of VolumeController \t"+this.value); this.value = value; System.out.println("New value of VolumeController \t"+this.value); } void adjust(int value) { int temp = this.get(); if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) { System.out.println("Can not adjust any further"); return; } this.set(temp + value); } } class BrightnessControllerV1 { private int value; int get() { return value; } void set(int value) { System.out.println("Old value of BrightnessController \t"+this.value); this.value = value; System.out.println("New value of BrightnessController \t"+this.value); } void adjust(int value) { int temp = this.get(); if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) { System.out.println("Can not adjust any further"); return; } this.set(temp + value); } } class ColourControllerV1 { private int value; int get() { return value; } void set(int value) { System.out.println("Old value of ColourController \t"+this.value); this.value = value; System.out.println("New value of ColourController \t"+this.value); } void adjust(int value) { int temp = this.get(); if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) { System.out.println("Can not adjust any further"); return; } this.set(temp + value); } } /* * There can be n number of controllers * */ public class TvApplicationV1 { public static void main(String[] args) { VolumeControllerV1 volumeControllerV1 = new VolumeControllerV1(); BrightnessControllerV1 brightnessControllerV1 = new BrightnessControllerV1(); ColourControllerV1 colourControllerV1 = new ColourControllerV1(); OUTER: while(true) { Scanner sc=new Scanner(System.in); System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume"); System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness"); System.out.println(" Press 5 to increase color \n Press 6 to decrease color"); System.out.println("Press any other Button to shutdown"); int button = sc.nextInt(); switch (button) { case 1: { volumeControllerV1.adjust(5); break; } case 2: { volumeControllerV1.adjust(-5); break; } case 3: { brightnessControllerV1.adjust(5); break; } case 4: { brightnessControllerV1.adjust(-5); break; } case 5: { colourControllerV1.adjust(5); break; } case 6: { colourControllerV1.adjust(-5); break; } default: System.out.println("Shutting down..........."); break OUTER; } } } } 

Теперь у вас есть первая версия рабочего приложения, готовая к развертыванию. Время проанализировать проделанную работу.

Проблемы в телевизионной версии приложения 1

  1. Код корректировки (int value) дублируется во всех трех classах. Вы хотели бы свести к минимуму дублирование кода. (Но вы не думали о распространенном коде и перемещали его в какой-то суперclass, чтобы избежать дублирования кода)

Вы решаете жить с этим, пока ваше приложение работает так, как ожидалось.

Иногда ваш босс возвращается к вам и просит добавить функциональность сброса в существующее приложение. Сброс установил бы все 3 три controllerа на соответствующие значения по умолчанию.

Вы начинаете писать новый class (ResetFunctionV2) для новых функций и сопоставляете код отображения ввода пользователя для этой новой функции.

Версия приложения 2

 import java.util.Scanner; class VolumeControllerV2 { private int defaultValue = 25; private int value; int getDefaultValue() { return defaultValue; } int get() { return value; } void set(int value) { System.out.println("Old value of VolumeController \t"+this.value); this.value = value; System.out.println("New value of VolumeController \t"+this.value); } void adjust(int value) { int temp = this.get(); if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) { System.out.println("Can not adjust any further"); return; } this.set(temp + value); } } class BrightnessControllerV2 { private int defaultValue = 50; private int value; int get() { return value; } int getDefaultValue() { return defaultValue; } void set(int value) { System.out.println("Old value of BrightnessController \t"+this.value); this.value = value; System.out.println("New value of BrightnessController \t"+this.value); } void adjust(int value) { int temp = this.get(); if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) { System.out.println("Can not adjust any further"); return; } this.set(temp + value); } } class ColourControllerV2 { private int defaultValue = 40; private int value; int get() { return value; } int getDefaultValue() { return defaultValue; } void set(int value) { System.out.println("Old value of ColourController \t"+this.value); this.value = value; System.out.println("New value of ColourController \t"+this.value); } void adjust(int value) { int temp = this.get(); if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) { System.out.println("Can not adjust any further"); return; } this.set(temp + value); } } class ResetFunctionV2 { private VolumeControllerV2 volumeControllerV2 ; private BrightnessControllerV2 brightnessControllerV2; private ColourControllerV2 colourControllerV2; ResetFunctionV2(VolumeControllerV2 volumeControllerV2, BrightnessControllerV2 brightnessControllerV2, ColourControllerV2 colourControllerV2) { this.volumeControllerV2 = volumeControllerV2; this.brightnessControllerV2 = brightnessControllerV2; this.colourControllerV2 = colourControllerV2; } void onReset() { volumeControllerV2.set(volumeControllerV2.getDefaultValue()); brightnessControllerV2.set(brightnessControllerV2.getDefaultValue()); colourControllerV2.set(colourControllerV2.getDefaultValue()); } } /* * so on * There can be n number of controllers * * */ public class TvApplicationV2 { public static void main(String[] args) { VolumeControllerV2 volumeControllerV2 = new VolumeControllerV2(); BrightnessControllerV2 brightnessControllerV2 = new BrightnessControllerV2(); ColourControllerV2 colourControllerV2 = new ColourControllerV2(); ResetFunctionV2 resetFunctionV2 = new ResetFunctionV2(volumeControllerV2, brightnessControllerV2, colourControllerV2); OUTER: while(true) { Scanner sc=new Scanner(System.in); System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume"); System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness"); System.out.println(" Press 5 to increase color \n Press 6 to decrease color"); System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown"); int button = sc.nextInt(); switch (button) { case 1: { volumeControllerV2.adjust(5); break; } case 2: { volumeControllerV2.adjust(-5); break; } case 3: { brightnessControllerV2.adjust(5); break; } case 4: { brightnessControllerV2.adjust(-5); break; } case 5: { colourControllerV2.adjust(5); break; } case 6: { colourControllerV2.adjust(-5); break; } case 7: { resetFunctionV2.onReset(); break; } default: System.out.println("Shutting down..........."); break OUTER; } } } } 

So you have your application ready with Reset feature. But, now you start realizing that

Issues in TV Application Version 2

  1. If a new controller is introduced to the product, you have to change Reset feature code.
  2. If the count of the controller grows very high, you would have issue in holding the references of the controllers.
  3. Reset feature code is tightly coupled with all the controllers Class's code(to get and set default values).
  4. Reset feature class (ResetFunctionV2) can access other method of the Controller class's (adjust) which is undesirable.

At the same time, You hear from you Boss that you might have to add a feature wherein each of controllers, on start-up, needs to check for the latest version of driver from company's hosted driver repository via internet.

Now you start thinking that this new feature to be added resembles with Reset feature and Issues of Application (V2) will be multiplied if you don't re-factor your application.

You start thinking of using inheritance so that you can take advantage from polymorphic ability of JAVA and you add a new abstract class (ControllerV3) to

  1. Declare the signature of get and set method.
  2. Contain adjust method implementation which was earlier replicated among all the controllers.
  3. Declare setDefault method so that reset feature can be easily implemented leveraging Polymorphism.

With these improvements, you have version 3 of your TV application ready with you.

Application Version 3

 import java.util.ArrayList; import java.util.List; import java.util.Scanner; abstract class ControllerV3 { abstract void set(int value); abstract int get(); void adjust(int value) { int temp = this.get(); if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) { System.out.println("Can not adjust any further"); return; } this.set(temp + value); } abstract void setDefault(); } class VolumeControllerV3 extends ControllerV3 { private int defaultValue = 25; private int value; public void setDefault() { set(defaultValue); } int get() { return value; } void set(int value) { System.out.println("Old value of VolumeController \t"+this.value); this.value = value; System.out.println("New value of VolumeController \t"+this.value); } } class BrightnessControllerV3 extends ControllerV3 { private int defaultValue = 50; private int value; public void setDefault() { set(defaultValue); } int get() { return value; } void set(int value) { System.out.println("Old value of BrightnessController \t"+this.value); this.value = value; System.out.println("New value of BrightnessController \t"+this.value); } } class ColourControllerV3 extends ControllerV3 { private int defaultValue = 40; private int value; public void setDefault() { set(defaultValue); } int get() { return value; } void set(int value) { System.out.println("Old value of ColourController \t"+this.value); this.value = value; System.out.println("New value of ColourController \t"+this.value); } } class ResetFunctionV3 { private List controllers = null; ResetFunctionV3(List controllers) { this.controllers = controllers; } void onReset() { for (ControllerV3 controllerV3 :this.controllers) { controllerV3.setDefault(); } } } /* * so on * There can be n number of controllers * * */ public class TvApplicationV3 { public static void main(String[] args) { VolumeControllerV3 volumeControllerV3 = new VolumeControllerV3(); BrightnessControllerV3 brightnessControllerV3 = new BrightnessControllerV3(); ColourControllerV3 colourControllerV3 = new ColourControllerV3(); List controllerV3s = new ArrayList<>(); controllerV3s.add(volumeControllerV3); controllerV3s.add(brightnessControllerV3); controllerV3s.add(colourControllerV3); ResetFunctionV3 resetFunctionV3 = new ResetFunctionV3(controllerV3s); OUTER: while(true) { Scanner sc=new Scanner(System.in); System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume"); System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness"); System.out.println(" Press 5 to increase color \n Press 6 to decrease color"); System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown"); int button = sc.nextInt(); switch (button) { case 1: { volumeControllerV3.adjust(5); break; } case 2: { volumeControllerV3.adjust(-5); break; } case 3: { brightnessControllerV3.adjust(5); break; } case 4: { brightnessControllerV3.adjust(-5); break; } case 5: { colourControllerV3.adjust(5); break; } case 6: { colourControllerV3.adjust(-5); break; } case 7: { resetFunctionV3.onReset(); break; } default: System.out.println("Shutting down..........."); break OUTER; } } } } 

Although most of the Issue listed in issue list of V2 were addressed except

Issues in TV Application Version 3

  1. Reset feature class (ResetFunctionV3) can access other method of the Controller class's (adjust) which is undesirable.

Again, you think of solving this problem, as now you have another feature (driver update at startup) to implement as well. If you don't fix it, it will get replicated to new features as well.

So you divide the contract defined in abstract class and write 2 interfaces for

  1. Reset feature.
  2. Driver Update.

And have your 1st concrete class implement them as below

Application Version 4

 import java.util.ArrayList; import java.util.List; import java.util.Scanner; interface OnReset { void setDefault(); } interface OnStart { void checkForDriverUpdate(); } abstract class ControllerV4 implements OnReset,OnStart { abstract void set(int value); abstract int get(); void adjust(int value) { int temp = this.get(); if(((value > 0) && (temp >= 100)) || ((value < 0) && (temp <= 0))) { System.out.println("Can not adjust any further"); return; } this.set(temp + value); } } class VolumeControllerV4 extends ControllerV4 { private int defaultValue = 25; private int value; @Override int get() { return value; } void set(int value) { System.out.println("Old value of VolumeController \t"+this.value); this.value = value; System.out.println("New value of VolumeController \t"+this.value); } @Override public void setDefault() { set(defaultValue); } @Override public void checkForDriverUpdate() { System.out.println("Checking driver update for VolumeController .... Done"); } } class BrightnessControllerV4 extends ControllerV4 { private int defaultValue = 50; private int value; @Override int get() { return value; } @Override void set(int value) { System.out.println("Old value of BrightnessController \t"+this.value); this.value = value; System.out.println("New value of BrightnessController \t"+this.value); } @Override public void setDefault() { set(defaultValue); } @Override public void checkForDriverUpdate() { System.out.println("Checking driver update for BrightnessController .... Done"); } } class ColourControllerV4 extends ControllerV4 { private int defaultValue = 40; private int value; @Override int get() { return value; } void set(int value) { System.out.println("Old value of ColourController \t"+this.value); this.value = value; System.out.println("New value of ColourController \t"+this.value); } @Override public void setDefault() { set(defaultValue); } @Override public void checkForDriverUpdate() { System.out.println("Checking driver update for ColourController .... Done"); } } class ResetFunctionV4 { private List controllers = null; ResetFunctionV4(List controllers) { this.controllers = controllers; } void onReset() { for (OnReset onreset :this.controllers) { onreset.setDefault(); } } } class InitializeDeviceV4 { private List controllers = null; InitializeDeviceV4(List controllers) { this.controllers = controllers; } void initialize() { for (OnStart onStart :this.controllers) { onStart.checkForDriverUpdate(); } } } /* * so on * There can be n number of controllers * * */ public class TvApplicationV4 { public static void main(String[] args) { VolumeControllerV4 volumeControllerV4 = new VolumeControllerV4(); BrightnessControllerV4 brightnessControllerV4 = new BrightnessControllerV4(); ColourControllerV4 colourControllerV4 = new ColourControllerV4(); List controllerV4s = new ArrayList<>(); controllerV4s.add(brightnessControllerV4); controllerV4s.add(volumeControllerV4); controllerV4s.add(colourControllerV4); List controllersToInitialize = new ArrayList<>(); controllersToInitialize.addAll(controllerV4s); InitializeDeviceV4 initializeDeviceV4 = new InitializeDeviceV4(controllersToInitialize); initializeDeviceV4.initialize(); List controllersToReset = new ArrayList<>(); controllersToReset.addAll(controllerV4s); ResetFunctionV4 resetFunctionV4 = new ResetFunctionV4(controllersToReset); OUTER: while(true) { Scanner sc=new Scanner(System.in); System.out.println(" Enter your option \n Press 1 to increase volume \n Press 2 to decrease volume"); System.out.println(" Press 3 to increase brightness \n Press 4 to decrease brightness"); System.out.println(" Press 5 to increase color \n Press 6 to decrease color"); System.out.println(" Press 7 to reset TV \n Press any other Button to shutdown"); int button = sc.nextInt(); switch (button) { case 1: { volumeControllerV4.adjust(5); break; } case 2: { volumeControllerV4.adjust(-5); break; } case 3: { brightnessControllerV4.adjust(5); break; } case 4: { brightnessControllerV4.adjust(-5); break; } case 5: { colourControllerV4.adjust(5); break; } case 6: { colourControllerV4.adjust(-5); break; } case 7: { resetFunctionV4.onReset(); break; } default: System.out.println("Shutting down..........."); break OUTER; } } } } 

Now all of the issue faced by you got addressed and you realized that with the use of Inheritance and Polymorphism you could

  1. Keep various part of application loosely coupled.( Reset or Driver Update feature components don't need to be made aware of actual controller classes(Volume, Brightness and Colour), any class implementing OnReset or OnStart will be acceptable to Reset or Driver Update feature components respectively).
  2. Application enhancement becomes easier.(New addition of controller wont impact reset or driver update feature component, and it is now really easy for you to add new ones)
  3. Keep layer of abstraction.(Now Reset feature can see only setDefault method of controllers and Reset feature can see only checkForDriverUpdate method of controllers)

Hope, this helps 🙂

Polymorphism relates to the ability of a language to have different object treated uniformly by using a single interfaces; as such it is related to overriding, so the interface (or the base class) is polymorphic, the implementor is the object which overrides (two faces of the same medal)

anyway, the difference between the two terms is better explained using other languages, such as c++: a polymorphic object in c++ behaves as the java counterpart if the base function is virtual, but if the method is not virtual the code jump is resolved statically , and the true type not checked at runtime so, polymorphism include the ability for an object to behave differently depending on the interface used to access it; let me make an example in pseudocode:

 class animal { public void makeRumor(){ print("thump"); } } class dog extends animal { public void makeRumor(){ print("woff"); } } animal a = new dog(); dog b = new dog(); a.makeRumor() -> prints thump b.makeRumor() -> prints woff 

(supposing that makeRumor is NOT virtual)

java doesn’t truly offer this level of polymorphism (called also object slicing).

animal a = new dog(); dog b = new dog();

 a.makeRumor() -> prints thump b.makeRumor() -> prints woff 

on both case it will only print woff.. since a and b is refering to class dog

 import java.io.IOException; class Super { protected Super getClassName(Super s) throws IOException { System.out.println(this.getClass().getSimpleName() + " - I'm parent"); return null; } } class SubOne extends Super { @Override protected Super getClassName(Super s) { System.out.println(this.getClass().getSimpleName() + " - I'm Perfect Overriding"); return null; } } class SubTwo extends Super { @Override protected Super getClassName(Super s) throws NullPointerException { System.out.println(this.getClass().getSimpleName() + " - I'm Overriding and Throwing Runtime Exception"); return null; } } class SubThree extends Super { @Override protected SubThree getClassName(Super s) { System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Returning SubClass Type"); return null; } } class SubFour extends Super { @Override protected Super getClassName(Super s) throws IOException { System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and Throwing Narrower Exception "); return null; } } class SubFive extends Super { @Override public Super getClassName(Super s) { System.out.println(this.getClass().getSimpleName()+ " - I'm Overriding and have broader Access "); return null; } } class SubSix extends Super { public Super getClassName(Super s, String ol) { System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading "); return null; } } class SubSeven extends Super { public Super getClassName(SubSeven s) { System.out.println(this.getClass().getSimpleName()+ " - I'm Perfect Overloading because Method signature (Argument) changed."); return null; } } public class Test{ public static void main(String[] args) throws Exception { System.out.println("Overriding\n"); Super s1 = new SubOne(); s1.getClassName(null); Super s2 = new SubTwo(); s2.getClassName(null); Super s3 = new SubThree(); s3.getClassName(null); Super s4 = new SubFour(); s4.getClassName(null); Super s5 = new SubFive(); s5.getClassName(null); System.out.println("Overloading\n"); SubSix s6 = new SubSix(); s6.getClassName(null, null); s6 = new SubSix(); s6.getClassName(null); SubSeven s7 = new SubSeven(); s7.getClassName(s7); s7 = new SubSeven(); s7.getClassName(new Super()); } } 
Interesting Posts
Давайте будем гением компьютера.