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

StackOverflow https://stackoverflow.com/questions/154577

Вопрос

С точки зрения Java, когда кто-то спрашивает:

что такое полиморфизм?

Бы перегрузка или переопределяющий быть приемлемым ответом?

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

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

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

Это было полезно?

Решение

Самый ясный способ выразить полиморфизм — через абстрактный базовый класс (или интерфейс).

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

Этот класс является абстрактным, поскольку goPee() метод не поддается определению для людей.Его можно определить только для подклассов Мужской и Женский.Кроме того, Человек — это абстрактное понятие. Вы не можете создать человека, который не был бы ни мужчиной, ни женщиной.Должно быть одно или другое.

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

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<Human> group = new ArrayList<Human>();
    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
...

Другие советы

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

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

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

Вот пример полиморфизма в псевдо-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 ());
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Полиморфизм просто означает «Множество форм».

Для достижения этого НЕ ТРЕБУЕТСЯ наследование... поскольку реализация интерфейса, которая вообще не является наследованием, служит полиморфным потребностям.Можно утверждать, что реализация интерфейса удовлетворяет полиморфные потребности «лучше», чем наследование.

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

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

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

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

Это то, что я называю полиморфизмом.

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

Ни один:

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

Переопределение — это когда дочерний класс заменяет родительский метод своим собственным (это само по себе не является полиморфизмом).

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

В Java вы часто видите полиморфизм в библиотеке коллекций:

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

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

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

Если бы вы перегружали, у вас было бы:

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

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

Термин «перегрузка» означает наличие нескольких версий чего-то с одним и тем же именем, обычно методов с разными списками параметров.

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

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

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

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

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

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

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

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

что такое полиморфизм?

Из Явы руководство

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

Рассмотрев примеры и определения, переопределяющий должен быть принят ответ.

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

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

Это следует назвать переопределением.

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

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

фрагмент кода:

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:

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

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

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

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

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

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

Почему полиморфизм так важен в любом ООП-языке.

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

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

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

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

Версия приложения 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) дублируется во всех трех классах.Вы хотите свести к минимуму дублирование кода.(Но вы не подумали об общем коде и переносе его в какой-то суперкласс, чтобы избежать дублирования кода)

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

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

Вы начинаете писать новый класс (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;
            }

        }
    }
}

Итак, у вас есть готовое приложение с функцией сброса.Но теперь ты начинаешь это понимать

Проблемы в версии 2 ТВ-приложения

  1. Если в продукт добавлен новый контроллер, вам необходимо изменить код функции сброса.
  2. Если количество контроллеров станет очень большим, у вас возникнут проблемы с сохранением ссылок на контроллеры.
  3. Код функции сброса тесно связан с кодом всех классов контроллеров (для получения и установки значений по умолчанию).
  4. Класс объектов сброса (ResetFunctionV2) может получить доступ к другому методу класса Controller (adjust), что нежелательно.

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

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

Вы начинаете думать об использовании наследования, чтобы воспользоваться полиморфными возможностями JAVA, и добавляете новый абстрактный класс (ControllerV3) в

  1. Объявите подпись методов get и set.
  2. Содержит реализацию метода настройки, которая ранее была воспроизведена среди всех контроллеров.
  3. Объявите метод setDefault, чтобы можно было легко реализовать функцию сброса с использованием полиморфизма.

Благодаря этим улучшениям у вас есть готовая версия 3 вашего ТВ-приложения.

Версия приложения 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<ControllerV3> controllers = null;

    ResetFunctionV3(List<ControllerV3> 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<ControllerV3> 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;
            }

        }
    }
}

Хотя большая часть проблем, перечисленных в списке проблем версии 2, была решена, за исключением

Проблемы в приложении TV версии 3

  1. Класс объектов сброса (ResetFunctionV3) может получить доступ к другому методу класса Controller (adjust), что нежелательно.

Опять же, вы думаете о решении этой проблемы, так как теперь вам нужно реализовать еще одну функцию (обновление драйверов при запуске).Если вы не исправите это, оно также будет реплицировано на новые функции.

Итак, вы разделяете контракт, определенный в абстрактном классе, и пишете 2 интерфейса для

  1. Функция сброса.
  2. Обновление драйверов.

И пусть ваш первый конкретный класс реализует их, как показано ниже.

Версия приложения 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<OnReset> controllers = null;

    ResetFunctionV4(List<OnReset> controllers)  {
        this.controllers = controllers;
    }
    void onReset()    {
        for (OnReset onreset :this.controllers)  {
            onreset.setDefault();
        }
    }
}
class InitializeDeviceV4 {

    private List<OnStart> controllers = null;

    InitializeDeviceV4(List<OnStart> 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<ControllerV4> controllerV4s = new ArrayList<>();
        controllerV4s.add(brightnessControllerV4);
        controllerV4s.add(volumeControllerV4);
        controllerV4s.add(colourControllerV4);

        List<OnStart> controllersToInitialize = new ArrayList<>();
        controllersToInitialize.addAll(controllerV4s);
        InitializeDeviceV4 initializeDeviceV4 = new InitializeDeviceV4(controllersToInitialize);
        initializeDeviceV4.initialize();

        List<OnReset> 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;
            }

        }
    }
}

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

  1. Сохраняйте различные части приложения слабосвязанными. (Компоненты функций сброса или обновления драйверов не должны быть осведомлены о реальных классах контроллера (громкость, яркость и цвет), любой класс, реализующий функции OnReset или OnStart, будет приемлем для функций сброса или обновления драйверов. компоненты соответственно).
  2. Улучшение приложений становится проще. (Новое добавление контроллера не повлияет на компонент функции сброса или обновления драйвера, и теперь вам очень легко добавлять новые)
  3. Сохраняйте уровень абстракции. (Теперь функция сброса может видеть только метод контроллеров setDefault, а функция сброса может видеть только метод контроллеров checkForDriverUpdate)

Надеюсь это поможет :-)

Полиморфизм более вероятен, поскольку это значение обеспокоен ...переопределить в Java

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

Думаю, приведенный ниже пример поможет вам понять...Хотя это не ЧИСТЫЙ Java-код...

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

А вот если поменять АРГУМЕНТ...ПОВЕДЕНИЕ изменится...

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

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

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

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

в любом случае разницу между этими двумя терминами лучше объяснить, используя другие языки, например C++:полиморфный объект в С++ ведет себя как аналог Java, если базовая функция виртуальна, но если метод не виртуальный, разрешается переход кода статически, а истинный тип не проверяется во время выполнения, поэтому полиморфизм включает в себя способность объекта вести себя по-разному в зависимости от интерфейса, используемого для доступа к нему;позвольте мне сделать пример в псевдокоде:

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

(предположим, что makeRumor НЕ виртуален)

Java на самом деле не предлагает такой уровень полиморфизма (также называемый нарезкой объектов).

животное a = новая собака();собака b = новая собака();

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

в обоих случаях будет печатать только woff..поскольку a и b относятся к классу собака

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

    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top