“Абстрактный статический” метод - как?

Уже существуют несколько ТАК вопросы, на том, почему нет абстрактного статического метода / поля как такового, но я задаюсь вопросом о том, как можно было бы пойти о реализации следующего psuedo-кода:

class Animal {
    abstract static int getNumberOfLegs(); // not possible
}

class Chicken inherits Animal {
    static int getNumberOfLegs() { return 2; }


class Dog inherits Animal {
    static int getNumberOfLegs() { return 4; }

Вот проблема: Предположение, что я хочу, удостоверяется, что каждый класс, который наследовался Animal содержать getNumberOfLegs() метод (т.е. почти как интерфейс, кроме я действительно хочу, чтобы абстрактный класс реализовал несколько методик, которые характерны для всех дочерних классов, следовательно чистый интерфейс не работает здесь). getNumberOfLegs() очевидно, должен быть статический метод (предполагающий, что в идеальном мире у нас' нет цыпленка, которому наносят вред, и собак так getNumberOfLegs не зависимо от экземпляра).

Без "абстрактного статического" метода/поля можно или оставить метод из Animal класс, затем существует риск, что некоторый дочерний класс не имеет того метода. Или можно сделать getNumberOfLegs метод экземпляра, но затем нужно было бы инстанцировать класса для обнаружения, сколько участков, которые животное имеет - даже при том, что это не необходимо.

Как каждый обычно идет о реализации этой ситуации?


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

Animal getModelAnimal(int numberOfLegs) {
   if (numberOfLegs == Chicken.getNumberOfLegs()) return new Chicken();
   else if (numberOfLegs == Dog.getNumberOfLegs()) return new Dog();
}
12
задан Jonik 30 May 2010 в 00:06
поделиться

10 ответов

Как обычно реализуется такая ситуация?

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

abstract class Animal {
    private int numberOfLegs;

    public Animal(int numberOfLegs) {
        this.numberOfLegs = numberOfLegs;
    }

    public int getNumberOfLegs() {
        return numberOfLegs;
    }
}

class Chicken extends Animal {
    public Chicken() {
        super(2);
    }
}

class Dog extends Animal {
    public Dog() {
        super(4);
    }
}

Обновление: в соответствии с вашим обновлением

EDIT: Вот как я мог бы это использовать. Предположим (сейчас это смешно, но как бы то ни было...), что количество ног у каждого животного уникально, поэтому я мог бы что-то вроде:

Animal getModelAnimal(int numberOfLegs) {
 if (numberOfLegs == Chicken.getNumberOfLegs()) return new Chicken();
 else if (numberOfLegs == Dog.getNumberOfLegs()) return new Dog();
}

Это действительно нелепо, это требует, чтобы все эти конкретные животные были известны заранее в методе абстрактной фабрики. Вам придется обновлять метод абстрактной фабрики каждый раз, когда добавляется новый тип конкретного животного. В чем тогда смысл абстрактной фабрики? Вы уже все знаете заранее? Нет, просто пусть метод абстрактной фабрики принимает полное квалифицированное имя класса в качестве идентификатора или около того, чтобы он мог попытаться загрузить его из classpath (все еще говоря в терминах Java).

2
ответ дан 2 December 2019 в 21:42
поделиться

Абстрактные методы имеют смысл, если вы вызываете их в помощь базовому классу. Обратите внимание, что в вашем примере вы вообще не используете полиморфизм. В примере должно быть что-то вроде:

  (Animal)Dog.getNumberOfLegs() //cast Dog to Animal first

В любом случае, PHP реализует так называемое "позднее статическое связывание", что, вероятно, и есть то, что вы ищете

http://php.net/manual/en/language.oop5.late-static-bindings.php

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

0
ответ дан 2 December 2019 в 21:42
поделиться

abstract static методы имеют смысл только в языках, в которых переменные могут содержать реальные типы, а не только экземпляры. (Delphi - один из таких языков, c# - нет, и я не думаю, что вы можете сделать это в Java). Причина в том, что если во время компиляции вы точно знаете, какие классы вы используете (как в вашем примере), то нет причин для того, чтобы метод был абстрактным, вы можете просто иметь статические методы в каждом классе с одинаковыми именами. Единственный способ, при котором вы можете не знать, какие типы вы используете, это если вы можете присвоить типы переменной, поскольку тогда вы можете передавать их по кругу (как экземпляры классов), и внезапно все приобретает смысл и становится полезным.

Я думаю, что большинство компиляторов / языков, поддерживающих присвоение типов (а также экземпляров типов) переменным, также поддерживают методы abstract static и virtual abstract с помощью магии компилятора, так что если они действительно полезны в выбранном вами языке, то они должны поддерживаться.

0
ответ дан 2 December 2019 в 21:42
поделиться

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

0
ответ дан 2 December 2019 в 21:42
поделиться

Еще один подход, который я вижу здесь, - это создание абстрактной фабрики: это c # вам не нужно создавать экземпляр Chicken, чтобы знать количество ножек. просто вызовите фабричный метод проверки

abstract class AnimalFactory
{
    public abstract Animal CreateAnimal();
    public abstract int GetLegs();

}
abstract class Animal
{

}
internal class Chicken : Animal
{

}
class CreateChicken : AnimalFactory
{
    public override Animal CreateAnimal()
    {
        return new Chicken();
    }
    public override int GetLegs()
    {
        return 2;
    }

}
0
ответ дан 2 December 2019 в 21:42
поделиться

Как обычно делаешь реализуете эту ситуацию?

Обычное решение - сделать рассматриваемый метод методом экземпляра.

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

Это категорически не очевидно! Мы не программируем для идеального мира, и в реальном мире четвероногие животные иногда имеют одну, две или три (или пять) ног.

Если вашей программе нужны определения животных , а не экземпляры животных , создайте класс для , который .

class AnimalDefinition {
    public string getScientificName();
    public string getCommonName();
    public int    getNumberOfLegs();
    public bool   getIsAmphibious();
    // etc.
}

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

4
ответ дан 2 December 2019 в 21:42
поделиться

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

В предоставленном вами варианте использования, например, фабричный метод обращается к конкретным классам животных по имени; для каждого нового класса животных должен быть добавлен новый конкретный код. Таким образом, кажется, что «абстрактная» квалификация на самом деле не нужна. Соглашения о предоставлении статического метода getNumberLegs () достаточно.

И вообще, объединение абстрактного и статического не имеет смысла (в Java), поскольку abstract подразумевает полиморфизм, а вызовы static вообще не являются полиморфными и работают с известными классами. во время компиляции.

0
ответ дан 2 December 2019 в 21:42
поделиться

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

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

Из http://forums.sun.com/thread.jspa?threadID=597378

Пожалуйста, посмотрите также Почему я не могу определить статический метод в интерфейсе Java?

3
ответ дан 2 December 2019 в 21:42
поделиться

Это действительно хорошая мысль, и иногда abstract static действительно не хватает. Однако, поскольку сейчас память не является проблемой, вы можете реализовать getNumberLegs()-метод как метод экземпляра.

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

Также неверно говорить, что статические методы не могут быть переопределены; final методы не могут быть переопределены. В таких языках, как Java и C#, static сопровождается final. Поэтому многие считают, что static равнозначно "не переопределяемому".

Говоря о C# (прочитав ваши комментарии, я предполагаю, что вы "говорите" на C#), вы можете рассмотреть возможность использования generics и атрибутов (или generics и аннотаций в Java):

public class Animal
{
   public static int GetNumberOfLegs<T>() where T : Animal
   {
     //Get T's custom attribute "NumberOfLegs" and return its value 
   }

   //EDIT: Added runtime-version of GetNumberOfLegs.
   public static int GetNumberOfLegs(Type t)
   {
     //Get t's custom attribute "NumberOfLegs" and return its value 

   }
}

[NumberOfLegs(4)]
public class Cat { ... };

Это позволит вам получить количество ног каждого типа без его инстанцирования. Только не забудьте указать атрибут [NumberOfLegs(x)]. Вы также должны знать тип во время компиляции (для общей версии метода).

EDIT: Я добавил runtime версию GetNumberOfLegs()-метода, которому можно передать объект Type (должен быть Class для Java). В этом случае вам придется выполнить проверку типа во время выполнения, то есть проверить, наследует ли тип, представленный Type-/Class-объектом, от Animal, а затем получить значение, переданное в атрибуте/аннотации.

Usage:

int numberOfLegs1 = Animal.GetNumberOfLegs<Cat>(); 
int numberOfLegs2 = Animal.GetNumberOfLegs(typeof(Cat)); //runtime version
3
ответ дан 2 December 2019 в 21:42
поделиться

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

0
ответ дан 2 December 2019 в 21:42
поделиться