Polimorfismo vs Overriding vs Sobrecarga

Em termos de Java, quando alguém pergunta:

o que é polymorphism?

Sobrecarregar ou ignorar seria uma resposta aceitável?

Eu acho que há um pouco mais do que isso.

Se você tivesse uma class base abstrata que definisse um método sem nenhuma implementação, e você definisse esse método na subclass, isso ainda está sendo sobreposto?

Eu acho que a sobrecarga não é a resposta certa, com certeza.

A maneira mais clara de expressar o polymorphism é através de uma class base abstrata (ou interface)

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

Esta class é abstrata porque o método goPee() não é definível para seres humanos. Só é definível para as subclasss Masculino e Feminino. Além disso, o humano é um conceito abstrato – você não pode criar um humano que não seja nem masculino nem feminino. Tem que ser um ou outro.

Então nós adiamos a implementação usando a class abstrata.

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

e

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

Agora podemos contar uma sala inteira cheia de humanos para fazer xixi.

 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(); } 

Correndo isto produziria:

 Stand Up Sit Down ... 

Polimorfismo é a capacidade de uma instância de class se comportar como se fosse uma instância de outra class em sua tree de inheritance, na maioria das vezes uma de suas classs ancestrais. Por exemplo, em Java, todas as classs são herdadas de Object. Portanto, você pode criar uma variável do tipo Object e atribuir a ela uma instância de qualquer class.

Um override é um tipo de function que ocorre em uma class que herda de outra class. Uma function de substituição “substitui” uma function herdada da class base, mas o faz de tal maneira que é chamada mesmo quando uma instância de sua class está fingindo ser um tipo diferente através de polymorphism. Referindo-se ao exemplo anterior, você poderia definir sua própria class e replace a function toString (). Como essa function é herdada de Object, ela ainda estará disponível se você copiar uma instância dessa class em uma variável do tipo Object. Normalmente, se você chamar toString () em sua class enquanto estiver fingindo ser um Object, a versão do toString que irá realmente triggersr é aquela definida no próprio Objeto. No entanto, como a function é uma substituição, a definição de toString () da sua class é usada mesmo quando o verdadeiro tipo da instância da class está oculto por trás do polymorphism.

Sobrecarga é a ação de definir vários methods com o mesmo nome, mas com parâmetros diferentes. Não está relacionado a substituição ou polymorphism.

Aqui está um exemplo de polymorphism no pseudo-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 ()); } 

A function Main não conhece o tipo do animal e depende do comportamento de uma implementação particular do método MakeNoise ().

Edit: Parece que Brian me bateu para o soco. Engraçado nós usamos o mesmo exemplo. Mas o código acima deve ajudar a esclarecer os conceitos.

Polimorfismo significa mais de uma forma, mesmo object realizando operações diferentes de acordo com o requisito.

O polymorphism pode ser alcançado usando duas maneiras, essas são

  1. Método substituindo
  2. Sobrecarga de método

Sobrecarga de método significa escrever dois ou mais methods na mesma class usando o mesmo nome de método, mas os parâmetros de passagem são diferentes.

Substituir o método significa que usamos os nomes dos methods nas classs diferentes, o que significa que o método da class pai é usado na class filha.

Em Java para alcançar o polymorphism, uma variável de referência de superclass pode conter o object de subclass.

Para alcançar o polymorphism, todo desenvolvedor deve usar os mesmos nomes de método no projeto.

Tanto a sobrecarga quanto a sobrecarga são usadas para alcançar o polymorphism.

Você poderia ter um método em uma class que é substituída em uma ou mais subclasss. O método faz coisas diferentes dependendo de qual class foi usada para instanciar um object.

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

Você também pode ter um método sobrecarregado com dois ou mais conjuntos de argumentos. O método faz coisas diferentes com base no (s) tipo (s) de argumento (s) passados ​​(s).

  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); } } 

Você está certo de que a sobrecarga não é a resposta.

Nenhum deles é predominante. Substituir é o meio pelo qual você obtém polymorphism. Polimorfismo é a capacidade de um object para variar o comportamento com base em seu tipo. Isso é melhor demonstrado quando o chamador de um object que exibe polymorphism não sabe qual tipo específico é o object.

Especificamente dizendo sobrecarga ou ignorar não dá a imagem completa. O polymorphism é simplesmente a capacidade de um object de especializar seu comportamento com base em seu tipo.

Eu discordaria de algumas das respostas aqui, pois a sobrecarga é uma forma de polymorphism (polymorphism paramétrico) no caso em que um método com o mesmo nome pode se comportar de maneira diferente, dando diferentes tipos de parâmetros. Um bom exemplo é a sobrecarga do operador. Você pode definir “+” para aceitar diferentes tipos de parâmetros – digamos, strings ou int’s – e, com base nesses tipos, “+” se comportará de maneira diferente.

O polymorphism também inclui methods de inheritance e sobrescritos, embora possam ser abstratos ou virtuais no tipo base. Em termos de polymorphism baseado em inheritance, o Java suporta apenas inheritance de class única, limitando o comportamento polimórfico ao de uma única cadeia de tipos de base. Java suporta a implementação de múltiplas interfaces, o que é outra forma de comportamento polimórfico.

O exemplo clássico, cães e gatos são animais, os animais têm o método makeNoise. Eu posso iterar através de uma série de animais chamando makeNoise neles e esperar que eles fizessem lá respectiva implementação.

O código de chamada não precisa saber qual animal específico ele é.

Isso é o que eu penso como polymorphism.

Polimorfismo é a capacidade de um object aparecer em vários formulários. Isso envolve o uso de inheritance e funções virtuais para construir uma família de objects que podem ser trocados. A class base contém os protótipos das funções virtuais, possivelmente não implementadas ou com implementações padrão conforme o aplicativo determina, e as várias classs derivadas as implementam de maneira diferente para afetar diferentes comportamentos.

Nem:

Sobrecarga é quando você tem o mesmo nome de function que usa parâmetros diferentes.

Substituir é quando uma class filha substitui o método de um pai por um deles (isso em si não constitui polymorphism).

O polymorphism é binding tardia, por exemplo, os methods da class base (pai) estão sendo chamados, mas não até que o aplicativo saiba qual é o object real – pode ser uma class filha cujos methods são diferentes. Isso ocorre porque qualquer class filha pode ser usada quando uma class base é definida.

Em Java, você vê bastante polymorphism na biblioteca de collections:

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

List é a class base, o compilador não tem nenhuma pista se você estiver contando com uma linked list, vetor, matriz ou uma implementação de lista personalizada, desde que aja como uma List:

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

Se você estivesse sobrecarregando, você teria:

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

e a versão correta de countStuff () seria selecionada pelo compilador para corresponder aos parâmetros.

Polimorfismo significa simplesmente “muitas formas”.

Não requer inheritance para alcançar … como implementação de interface, que não é inheritance, serve necessidades polimórficas. Indiscutivelmente, a implementação da interface atende às necessidades polimórficas “Melhor” que a inheritance.

Por exemplo, você criaria uma superclass para descrever todas as coisas que podem voar? Eu não deveria pensar. Você seria mais bem servido para criar uma interface que descreve o voo e deixá-lo assim.

Portanto, como as interfaces descrevem o comportamento e os nomes dos methods descrevem o comportamento (para o programador), não é muito difícil considerar a sobrecarga do método como uma forma menor de polymorphism.

O termo sobrecarga refere-se a ter várias versões de algo com o mesmo nome, geralmente methods com diferentes listas de parâmetros

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

Então, essas funções podem fazer a mesma coisa, mas você tem a opção de chamá-lo com um ID ou um nome. Não tem nada a ver com inheritance, classs abstratas, etc.

Substituir geralmente se refere ao polymorphism, como você descreveu na sua pergunta

Substituir é mais como ocultar um método herdado, declarando um método com o mesmo nome e assinatura como o método de nível superior (super método), isso adiciona um comportamento polimórfico à class. em outras palavras, a decisão de escolher o método de nível a ser chamado será feita em tempo de execução e não no tempo de compilation. isso leva ao conceito de interface e implementação.

Sobrescrevendo quando nós herdamos a class base e fazemos a class derivada então se na class derivada existe um método que tem o mesmo nome que o método (mesmo nome, mesmo argumento, mesmo tipo de retorno) define na class base então chamado 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(); } 

Saída: A bicicleta está funcionando com segurança …….. Para entender a substituição mais claramente, acesse: http://javabyroopam.blogspot.in/

Sobrecarga Simplesmente dois methods que possuem o mesmo nome, mas possuem uma lista de argumentos diferente, são chamados de sobrecarga.

  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); } } 

saída 30,20

o que é polymorphism?

Do tutorial java

A definição do dictionary de polymorphism refere-se a um princípio em biologia no qual um organismo ou espécie pode ter muitas formas ou estágios diferentes. Este princípio também pode ser aplicado à programação orientada a objects e linguagens como a linguagem Java. As subclasss de uma class podem definir seus próprios comportamentos exclusivos e ainda compartilhar algumas das mesmas funcionalidades da class pai.

Ao considerar os exemplos e a definição, a resposta deve ser aceita.

Em relação à sua segunda consulta:

Se você tivesse uma class base abstrata que definisse um método sem nenhuma implementação, e você definisse esse método na subclass, isso ainda está sendo sobreposto?

Deve ser chamado de overriding.

Dê uma olhada neste exemplo para entender diferentes tipos de substituição.

  1. A class base não fornece implementação e a subclass tem que replace o método completo – (resumo)
  2. Classe base fornece implementação padrão e subclass pode mudar o comportamento
  3. Subclass adiciona extensão à implementação da class base chamando super.methodName() como primeira instrução
  4. A class base define a estrutura do algoritmo (método Template) e a subclass replaceá uma parte do algoritmo

fragment de código:

 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-classs 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(); } } } 

saída:

 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: 

sobrecarga é quando você define 2 methods com o mesmo nome, mas diferentes parâmetros

Sobrescrevendo é onde você muda o comportamento da class base através de uma function com o mesmo nome em uma subclass.

Portanto, o polymorphism está relacionado à substituição, mas não à sobrecarga.

No entanto, se alguém me deu uma resposta simples de “substituição” para a pergunta “O que é polymorphism?” Eu pediria mais explicações.

O polymorphism é mais provável, no que diz respeito ao significado … ao OVERRIDING em java

É tudo sobre o comportamento diferente do mesmo object em diferentes situações (na forma de programação … você pode chamar ARGUMENTOS diferentes)

Acho que o exemplo abaixo irá ajudá-lo a entender … Embora não seja código java puro …

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

Mas se mudarmos o ARGUMENTO … o COMPORTAMENTO será alterado …

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

A pessoa (aqui o “object”) é o mesmo …

O polymorphism é uma implementação múltipla de um object ou você pode dizer várias formas de um object. Vamos dizer que você tem class Animals como a class base abstrata e tem um método chamado movement() que define a maneira como o animal se move. Agora, na realidade, temos diferentes tipos de animais e eles se movem de forma diferente, bem como alguns deles com duas pernas, outros com quatro e alguns sem pernas, etc. Para definir diferentes movement() de cada animal na Terra, precisamos aplicar polymorphism. No entanto, você precisa definir mais classs, por exemplo, a class Dogs Cats Fish etc. Depois, é necessário estender essas classs da class base Animals e replace seu método movement() por uma nova funcionalidade de movimento baseada em cada animal que você possui. Você também pode usar Interfaces para conseguir isso. A palavra chave aqui é predominante, a sobrecarga é diferente e não é considerada como polymorphism. Com a sobrecarga, você pode definir vários methods “com o mesmo nome”, mas com parâmetros diferentes no mesmo object ou class.

Eu acho que vocês estão misturando conceitos. Polimorfismo é a capacidade de um object se comportar de maneira diferente no tempo de execução. Para conseguir isso, você precisa de dois requisitos:

  1. Vinculação tardia
  2. Herança.

Tendo dito que a sobrecarga significa algo diferente de replace, dependendo do idioma que você está usando. Por exemplo, em Java não existe substituição, mas sobrecarga . Métodos sobrecarregados com assinaturas diferentes para sua class base estão disponíveis na subclass. Caso contrário, eles seriam substituídos (por favor, veja que eu quero dizer agora o fato de que não há como chamar seu método de class base de fora do object).

No entanto, em C ++ isso não é verdade. Qualquer método sobrecarregado , independentemente de a assinatura ser a mesma ou não (quantidade diferente, tipo diferente) é também substituído . Isto é, o método da class base não está mais disponível na subclass ao ser chamado de fora do object da subclass, obviamente.

Então a resposta é quando se fala em Java usando sobrecarga . Em qualquer outro idioma pode ser diferente, como acontece em c + +

Embora o polymorphism já seja explicado em grandes detalhes neste post, mas gostaria de colocar mais ênfase em por que parte dele.

Por que o polymorphism é tão importante em qualquer linguagem OOP.

Vamos tentar criar um aplicativo simples para uma TV com e sem inheritance / polymorphism. Postar cada versão do aplicativo, fazemos uma pequena retrospectiva.

Suponhamos que você seja um engenheiro de software em uma empresa de TV e seja solicitado que você crie softwares para controladores de Volume, Brilho e Cor para aumentar e diminuir seus valores no comando do usuário.

Você começa escrevendo classs para cada um desses resources adicionando

  1. set: – Para definir um valor de um controlador (supondo que este tenha código específico do controlador)
  2. get: – Para obter um valor de um controlador (supondo que este tenha código específico do controlador)
  3. ajuste: – Para validar a input e configurar um controlador (validações genéricas .. independentes dos controladores)
  4. mapeamento de input do usuário com controladores: – Para obter input do usuário e chamar controladores de acordo.

Versão do aplicativo 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; } } } } 

Agora você tem nossa primeira versão do aplicativo de trabalho pronta para ser implantada. Hora de analisar o trabalho feito até agora.

Problemas na versão 1 do aplicativo de TV

  1. O código Adjust (int value) é duplicado nas três classs. Você gostaria de minimizar a duplicidade do código. (Mas você não pensou em código comum e o move para alguma superclass para evitar código duplicado)

Você decide viver com isso desde que o aplicativo funcione conforme o esperado.

Depois, às vezes, seu chefe volta para você e pede para você adicionar a funcionalidade de redefinição ao aplicativo existente. Redefinir definiria todos os 3 três controladores para seus respectivos valores padrão.

Você começa a escrever uma nova class (ResetFunctionV2) para a nova funcionalidade e mapeia o código de mapeamento de input do usuário para esse novo recurso.

Versão do aplicativo 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 classs(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()); } }