Различие в стиле: IDictionary по сравнению со Словарем

Я не думаю, что вы можете использовать «существует» для целого числа в Perl, только для коллекций. Можете ли вы привести пример того, что вы имеете в виду в Perl, который соответствует вашему примеру в Java.

Если дано выражение, которое определяет элемент хеша или элемент массива, возвращает значение true, если указанный элемент в хеш или массиве когда-либо был инициализирован, даже если соответствующее значение не определено.

Это указывает, что это применимо только к элементам хеша или массива!

68
задан rein 20 October 2009 в 15:31
поделиться

13 ответов

If IDictionary is a "more generic" type than Dictionary then it makes sense to use the more generic type in declaring variables. That way you don't have to care as much about the implementing class assigned to the variable and you can change the type easily in the future without having to change a lot of following code. For example, in Java it's often considered better to do

List<Integer> intList=new LinkedList<Integer>();

than it is to do

LinkedList<Integer> intList=new LinkedList<Integer>();

That way I'm sure all following code treats the list as a List and not a LinkedList, making it easy in the future to switch out LinkedList for Vector or any other class which implements List. I'd say this is common to Java and good programming in general.

62
ответ дан 24 November 2019 в 14:13
поделиться

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

Dictionary1 dictionary = new Dictionary1();
dictionary.operation1(); // if operation1 is implemented only in Dictionary1() this will fail for every other implementation

Это лучше всего видно, когда вы скрываете конструкцию объекта:

IDictionary dictionary = DictionaryFactory.getDictionary(...);
1
ответ дан 24 November 2019 в 14:13
поделиться

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

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

Однако при объявлении методов члены класса , или интерфейсы, я думаю, что использование типа интерфейса заранее избавит вас от головной боли, вместо того, чтобы связывать общедоступный API с определенным типом класса.

1
ответ дан 24 November 2019 в 14:13
поделиться

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

Map map = new HashMap();
List list = new ArrayList();

Думаю, это просто обеспечивает слабую связь во многих ситуациях.

3
ответ дан 24 November 2019 в 14:13
поделиться

Коллекции Java включают множество реализаций. Поэтому мне намного проще использовать

List<String> myList = new ArrayList<String>();

. Затем в будущем, когда я пойму, что мне нужно, чтобы "myList" был потокобезопасным, просто изменил эту единственную строку на

List<String> myList = new Vector<String>();

и не менял никакой другой строки кода. Сюда также входят геттеры / сеттеры. Если вы посмотрите, например, на количество реализаций Map, вы поймете, почему это может быть хорошей практикой. На других языках, где есть только пара реализаций для чего-то (извините, не большой парень .NET), но в Objective-C действительно есть только NSDictionary и NSMutableDictionary. Так что это не имеет большого смысла.

Edit:

Не удалось затронуть одну из моих ключевых точек (только что упомянул это с помощью геттеров / сеттеров).

Вышеуказанное позволяет вам иметь:

public void setMyList(List<String> myList) {
    this.myList = myList;
}

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

3
ответ дан 24 November 2019 в 14:13
поделиться

Насколько я знаю, разработчики Java обычно используют абстракцию (и шаблоны проектирования) чаще, чем разработчики .NET. Это кажется еще одним примером: зачем объявлять конкретный класс, если он, по сути, будет работать только с членами интерфейса?

5
ответ дан 24 November 2019 в 14:13
поделиться

Эта практика не ограничивается только Java.

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

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

27
ответ дан 24 November 2019 в 14:13
поделиться

Ваш друг следует очень полезному принципу:

«Избавьтесь от деталей реализации»

14
ответ дан 24 November 2019 в 14:13
поделиться

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

3
ответ дан 24 November 2019 в 14:13
поделиться

Я столкнулся с такой же ситуацией с Java-разработчиком. Таким же образом он создает экземпляры коллекций и объектов для их интерфейса. Например,

IAccount account = new Account();

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

1
ответ дан 24 November 2019 в 14:13
поделиться

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

8
ответ дан 24 November 2019 в 14:13
поделиться

Вы всегда должны пытаться программировать для интерфейса, а не для конкретного класса.

На Java или любом другом объектно-ориентированном языке программирования.

В мире .NET обычно используется I , чтобы указать, что это интерфейс, который вы используете. Я думаю, что это более распространено, потому что в C # у них нет реализаций и extends для ссылки на наследование классов и интерфейсов.

Я думаю, сыворотка набрала бы

 class MyClass:ISome,Other,IMore 
 { 
 }

И вы можете сказать ISome и IMore - это интерфейсы, а Other - это класс

В Java есть в этом нет необходимости

 class MyClass extends Other implements Some, More {
 }

Концепция все еще применима, вам следует попробовать кодировать интерфейс.

7
ответ дан 24 November 2019 в 14:13
поделиться

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

public class Widget
{
    private Dictionary<string, string> map = new Dictionary<string, string>();
    public IDictionary<string, string> Map
    {
        get { return map; }
    }
}

позже может стать:


class SpecialMap<TKey, TValue> : IDictionary<TKey, TValue> { ... }

public class Widget
{
    private SpecialMap<string, string> map = new SpecialMap<string, string>();
    public IDictionary<string, string> Map
    {
        get { return map; }
    }
}

без изменения интерфейса виджета и необходимости изменения других код уже использует его.

4
ответ дан 24 November 2019 в 14:13
поделиться