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

Ограничения в подклассах ООП

В java, что является хорошим способом разработки вокруг подкласса, который уменьшает функциональность суперкласса?

Например, рассмотрим класс "Человек" , который имеет функцию "См." и подкласс "BlindMan", который не должен иметь эту функцию, но должен иметь все остальное, что имеет "Человек" .

Единственное решение, которое я могу придумать, - это абстрактный класс "Человек" и два подкласса "SeeingMan" и "BlindMan", при этом SeeinMan добавляет функцию "См.".

Однако проблема с этим решением заключается в том, что если я хочу добавить класс DeafMan - что он расширяет? SeeingMan? и что, если этот человек является глухим и слепым?

4b9b3361

Ответ 1

Я думаю, вы должны использовать композицию, а не наследование в этом случае, или иметь различные подклассы, составляющие человека.

Хотя я понимаю вашу логику, BaseClass - это контракт, который гарантирует, что все классы этого типа должны придерживаться этого поведения, наличие подкласса, который удаляет родительский метод, является большим НЕТ НЕТ.

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

Вот несколько решений:

Сделайте Человеческий состав BasicHumanFunctions, VisionSystem и т.д. Тогда у слепого будет только несколько из них.

class Human {
  private BasicHumanFunctions _basicFunctions; //contains breathe funcitonality.
  private VisionSystem _vision; //contains see
}

class BlindMan {
   private BasicHumanFunctions _basicFunctions;
}

Создание человеческого базового класса содержит только одно и то же поведение, которое все люди хотели бы вдохнуть и т.д., а затем создать HealthyHuman и BlindHuman и т.д., каждый из которых создает свои собственные методы. Затем вы можете использовать HealthHuman и подкласс, если вам нужно.

class Human {
   void breathe() {};
   // other Human basic functions;
} 

class HealthyHuman extends Human {
   void see() {};
   //other healthy human functions
}

class BlindHuman extends Human {
  void useCane() {};
}

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

class BlindHuman extends Human {
   private VoiceSubsystem _voice = new VoiceSybsystem();
   void speaker() {  _voice.speaker();}
}

Ответ 2

Важнейшим принципом является принцип замещения Лысков.

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

Например, можно сказать, что слепой человек все еще видит, только он получает только черные (или серые) снимки. Там также вопрос о законных слепых людях, которых вы хотите, все еще видит что-то в случае размытости или частичной картины.

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

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

Ответ 3

Перейдите для интерфейсов.

Определите интерфейс для CommonMan, который имеет общие свойства и использует отдельные интерфейсы. Для отдельных подклассов, которые имеют свои конкретные методы. Затем вы можете получить оба метода интерфейса.

Пример:

public class SpecificMan extends CommonMan implements specifiManInter

{

//methods of CommonMan

//Methods of SpecificMan 

}

Класс CommonMan:

public class CommonMan implements CommonManInter {

 //methods of CommonMan

}

Ответ 4

Дори имеет право утверждать композицию над наследованием. Ваш вопрос/проблема в значительной степени совпадает с проблемой летной рыбы. В этом примере, как мы должны обрабатывать существо, которое может летать и плавать?

enter image description here

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

enter image description here

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

Примечание. Трудно прочитать преимущества вышеупомянутого скриншота, так что вот они снова:

Преимущества
- Использовать композицию объекта над наследованием
- Заставляет разработчика принимать сознательное решение о поведении при его кодировании (в отличие от создания реализаций по умолчанию в базовом классе, которые разработчик должен помнить, чтобы переопределить).
- Абстрагируя различное поведение, он теперь доступен для использования другими клиентами.
- Быть более слабо связанным означает, что его легче придерживаться принципа открытого/закрытого, где код должен быть открыт для расширения, но закрыт для модификации.

Ответ 5

В классе Man добавьте hasEyes, который по умолчанию является истинным, а в BlindMan сделает его ложным по умолчанию (или сделайте слепые маннитуры человека, у которого их глаза были ограблены сразу после, например, BlindManFactory). Затем в Man See введите код так, чтобы, если у него нет глаз, он автоматически терпит неудачу.

Ответ 6

вы можете использовать boolean

например: isSeeing()

и в вашей функции вы можете использовать это в инструкции if else

Ответ 7

В java, что является хорошим способом разработки вокруг подкласса, который уменьшает функциональность суперкласса?

Что в основном спрашивает: "Как наследование может уменьшить функциональность?". Примером этого в Java, о котором я могу думать, является метод Collections # unmodifyableList, который гласит:

Возвращает немодифицируемое представление указанного списка. Этот метод позволяет модулям предоставлять пользователям доступ к внутренним спискам "только для чтения". Операции запроса в возвращенном списке "чтение" в указанный список и попытки изменить возвращенный список, будь то прямой или через его итератор, приводят к UnsupportedOperationException.

Итак, что бы я хотел, если захочу удалить определенную функцию. Однако убедитесь, что его использование является ясным, например. состояние в Javadoc BlindMan, которое see() приведет к Исключению.

Однако, если вы хотите "уменьшить" несколько функций, возможно, независимо друг от друга и меняя их со временем, я предпочел бы использовать переменные, кроме наследования. В конце концов, вы не расширяете суперкласс, так зачем злоупотреблять этим наследованием? У вас есть человек с разными свойствами.

Поведение методов необходимо документировать. Я мог бы подумать о следующем классе для вашего использования:

public class Human {
    private boolean seeing;

    public void setSeeing(boolean seeing) { ...}
    public boolean isSeeing() { ... }

    /**
     *  Returns what the human sees at the moment, or null
     *  if he/she can't see (seeing is false).
     */
    public String see() {
        if(seeing){
            return "I can see a tree!";
        }else{
            return null;
        }
    }

    // same goes for hearing
}

Ответ 8

Пусть человек делает все по-своему, дайте ему задания, а не команды.

Видение - часть какой-то деятельности, поэтому пусть он пользуется зрением (или нет) независимо.

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

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

Иногда вы хотите спросить их, что они видят (и не заботятся о том, что они слышат и т.д.). Затем просто спросите и ожидайте, что слепые (и другие слабовидящие) ничего не заметят.

Если вы хотите, чтобы люди были пассивными объектами и каким-то другим объектом для их обработки, один еще не упомянутый подход: посмотрите на программирование сущности-компонента, используемое в игровом программировании. В основном он использует композицию в общем виде. У объектов есть только тождество, компоненты содержат данные о каком-либо аспекте сущности (например, вид может быть, например, количество диоптрий или более полезная статистика) и системные наборы процессов объектов, которые имеют комбинацию компонентов, требуемую данной системой. Система взглядов может потребовать компонент зрелища и создать компонент увиденных событий, содержащих то, что сущности текущего объекта видят прямо сейчас. Другая система могла объединить результаты всех чувств и использовать ее для выполнения чего-то полезного.

Ответ 9

Например, рассмотрим класс "Человек", который имеет функцию "См." и подкласс "BlindMan", который не должен иметь эту функцию

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

Хорошая аналогия: a Writer имеет функцию flush(), но что делает эту функцию для StringWriter?

/**
 * Flush the stream.
 */
public void flush() { 
}

Ну, ничего. Там нечего смывать. ОК, но почему close() выбрасывает IOException?

public void close() throws IOException {
}

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

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

Ответ 10

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

например. в вашем сценарии: InablityException

вот так:

public interface Man {

    public Object see() throws InabilityException;
    public Object hear() throws InabilityException;

}

public class BlindMan implements Man {
    public Object see() throws InabilityException {
       throw new InabilityException("blind people don't see");
    }

    public Object hear() {
       return "what I hear";
    }
}

И наоборот для DeafMan.

То же самое работает, если Man является class вместо interface.

Вы могли бы (и должны) объединить это с ответом @Pataschu fooobar.com/questions/237832/... и throw Exception, если hasWorkingEyes() возвращает false.

Ответ 11

Интерфейсы:

Я определял бы оба поведения (BlindMan и SeeingMan) через интерфейсы, выставляя только вызовы, определяющие тип (BlindMan и SeeingMan). Вы не должны заботиться о том, каков фактический тип экземпляра внизу.

Абстрактный родительский класс:

Теперь вы можете объединить эти интерфейсы с "родительским" абстрактным классом, который имеет все поведение по умолчанию (как слепые, так и видящие, если вы тоже выбираете)

Объедините два:

public interface BlindMan {
         public void useBlindStick();
    }

   public interface SeeingMan {
        public void see();
   }


  public abstract class Man {
       public void useBlindStick() {
           //work
       }

       public void see() {
           //work
       }
  }


  public class SomeBlindMan extends Man implements BlindMan {
        //bla bla
  }


 public class SeeingMan extends Man implements SeeingMan {
       //bla bla
 }

Надеюсь, что это поможет

Ответ 12

Как насчет чего-то вроде этого:

 public class Man {

    Ears ears;

    Eyes eyes;

    }

    public class Eyes {

    public boolean canSee()

    }

    public class Ears {

    public boolean canListen()
    }

тогда логика будет выглядеть как...

if(man.getEyes().canSee()){ //not blind

}
else
{
//blind logic
}

if(man.getEars().canListen())
{
//Not Deaf
}

Ответ 13

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

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

Если вы хотите динамически добавлять поведение во время выполнения, выполните Decorator шаблон.

Связанные сообщения SE:

Реализует vs extends: Когда использовать? В чем разница?

Когда использовать шаблон декоратора?