Значение типов, класса, интерфейса? - PullRequest
1 голос
/ 06 января 2011

Найдите, что многие авторы взаимозаменяемо используют термин Тип и Класс. В некоторых учебниках, посвященных объектно-ориентированной модели, также используется термин «интерфейс».

Может ли кто-нибудь объяснить это простыми словами на основе объектно-ориентированного программирования в целом и C ++ / Java / объектно-ориентированной базы данных в частности.

Ответы [ 4 ]

3 голосов
/ 06 января 2011

A type - это классификация фрагмента данных, сообщающая вам, каковы его допустимые значения и допустимые операции. (Почти?) Все языки программирования имеют типы, хотя дисциплина набора значительно варьируется от одного языка к другому.

A class - это определенный вид типа в языках ООП, который определяется с помощью специального синтаксиса в самом языке (в отличие, скажем, от так называемых «нативных типов»). "как Java int или float или тому подобное, которые определяются самим языком). Класс обычно определяется в терминах структуры памяти и кодирования данных (так называемые переменные-члены ) и функций, которые над ними работают (так называемые функции-члены или методы ).

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

Это очень, очень, очень краткий обзор, который является своего рода упрощенной «средней формой» подхода нескольких языков к ним. Он игнорирует некоторые крайние случаи и такие вещи, как способность C ++ создавать вещи, которые являются промежуточным звеном между интерфейсом и классом. Он также игнорирует классы на функциональных языках, таких как Haskell, потому что дальнейшее повреждение вашего мозга здесь не является целью. ;)


отредактировано для добавления некоторых примеров

Вот некоторые декларации Java- , такие как , чтобы помочь закрепить концепции.

int myVariable1;

Эта переменная & mdash; myVariable1 & mdash; является собственным (или примитивным) типом, состоящим из 32-разрядного целочисленного значения со знаком, закодированного в нотации 2-дополнения. Он имеет известный диапазон (приблизительно от -2 миллиардов до +2 миллиардов) и известный набор операций (умножение, сложение, деление, модуль, вычитание, различные преобразования и т. Д.), Доступных для него.

class MyClass
{
  int myMemberVariable;
  int myOtherMemberVariable;
  int myMethod(int p) { myMemberVariable += p; myOtherMemberVariable = p; }
}
MyClass myVariable2 = new MyClass();

Здесь myVariable2 - это тип, определенный классом MyClass. MyClass определяет структуру памяти (которая в данном случае состоит из двух 32-разрядных целых чисел со знаком в нотации с дополнением 2s), а также одну операцию myMethod(), которая добавляет свой аргумент к myMemberVariable и устанавливает для него myOtherMemberVariable аргумент.

interface MyInterface
{
  int myInterfaceMethod(int p, int q);
}

Здесь MyInterface объявляет только набор операций (состоящий в данном случае из одной функции myInterfaceMethod()) без каких-либо переменных-членов и без какой-либо реализации. Это только говорит вам, что любой класс, который реализует этот интерфейс, гарантированно имеет метод с этой конкретной сигнатурой name + return value + arguments. Чтобы использовать его, вы должны создать класс, который реализует интерфейс.

class MyOtherClass implements MyInterface
{
  int myMember1;
  int myMember2;
  int myMember3;
  int myInterfaceMethod(int p, int q) { myMember1 = p; myMember2 = q; myMember3 = p - q; }
  int myNonInterfaceMethod() { return myMember1; }
}
MyOtherClass myVariable3 = new MyOtherClass();

Теперь myVariable3 определяется как тип с макетом памяти, состоящим из трех 32-разрядных целых чисел со знаком и двух операций. Это одна из тех операций, которую должен осуществить из-за всей части implements MyInterface. Таким образом, все, что ожидает (абстрактный) тип MyInterface, может использовать (конкретный) тип MyOtherClass, поскольку операция гарантированно будет там. Другой метод & mdash; myNonInterfaceMethod() & mdash; не исходит от MyInterface, поэтому что-то, что ожидает только MyInterface, не может использовать его, потому что не может знать, что оно существует.


далее отредактировано для добавления некоторых реальных вещей по запросу

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

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

class BankAccount
{
  String accountNumber;
  float balance;  /* DO NOT USE FLOATING POINT IN REAL FINANCIAL CODE! */
  int transaction_limit;
  float transaction(float change) {
    balance += change > transaction_limit ? transaction_limit : change;
    return balance;
  }
}

Теперь вы можете создать переменную этого типа и знать, что она будет содержать номер счета (который сам является типом String), баланс (который сам по себе является типом float - но НЕ ИСПОЛЬЗУЙТЕ ПЛАВАЮЩУЮ ТОЧКУ В РЕАЛЬНОМ МИРОВОМ ФИНАНСОВОМ КОДЕ! ) и лимит транзакции (который сам по себе является типом int). Вы также знаете, что можете выполнить транзакцию (творчески называемую transaction), которая проверит изменение по лимиту транзакции и изменит баланс. (Реальный класс для этого содержал бы намного больше и содержал бы много защитного материала, который я удалил в педагогических целях.)

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

interface Transactable
{
  float transaction(float change);
}

class BankAccount implements Transactable
{
  /* interior is identical */
}

class ReceivablesAccount implements Transactable
{
  float balance;
  float transaction(float change) { balance += change; }
}

Теперь все, что знает о Transactable типах, может использовать как экземпляры BankAccount, так и экземпляры ReceivablesAccount. Им не нужно знать, что банковские счета имеют лимиты транзакций, а счета дебиторской задолженности - нет. Им не нужно ничего знать о внутреннем представлении данных. Им не нужно знать особых случаев чего-либо. Они просто должны знать об одной функции по имени (transaction()) и все. (Если вы хотите более конкретно использовать это в реальных условиях, посмотрите, как классы коллекций, не говоря уже о цикле for, используют интерфейс Iterable в Java.)

3 голосов
/ 06 января 2011

На языке O.O.P очень часто используются термины «Тип» и «Класс» взаимозаменяемо, особенно когда речь идет о некоторых языках, таких как Java и / или C ++.

Вообще говоря, когда вы определяете класс, вы на самом деле определяете шаблон Type , из которого будут создаваться и / или создаваться экземпляры определяемых вами объектов Type . ,

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

Для многих практических целей вы можете обращаться с Объектом по всему его интерфейсу так, как если бы он имел тип интерфейса, поэтому, вероятно, термин «интерфейс» используется взаимозаменяемо с термином «тип».

См. Теорию, лежащую в основе Абстрактные типы данных , для дальнейшего понимания.

1 голос
/ 06 января 2011

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

Большинство языков знают только об очень простых, примитивных «типах» таких вещей, как целые числа, символы и байты. Мы могли бы полностью использовать эти примитивные типы для описания типов вещей на кухне. Например, вы можете создать массив из массива символов, где каждый индекс в массиве представляет атрибут чего-либо. Например, индекс 0 представляет «тип» того, что вы пытаетесь описать. Но, конечно, эта техника очень быстро усложняется.

Таким образом, используя объектно-ориентированные методы, мы можем легко определить новые типы, комбинируя примитивные типы. Вы делаете это путем создания определения класса. Думайте о Классе как о проекте для нового Типа.

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

public class Food {...}
public class Appliance {...}
public class Furniture {...}

Интерфейс описывает, как мы можем взаимодействовать с чем-то. Например, мы хотим создать инвентарь вещей на нашей кухне. Мы хотим иметь возможность «Добавить» в наш инвентарь, «Удалить» вещи из нашего инвентаря и, возможно, «Итерировать» по нашему инвентарю. Действия «Добавить», «Удалить» и «Итерация» применяются практически ко всем спискам чего-либо (не только к нашему инвентарю). Java предоставляет интерфейс с именем «Список» для этой цели. Создав объект инвентаризации с очень популярным и распространенным списком «Интерфейс», мы получаем все действия бесплатно, а другие программисты могут посмотреть на нашу программу и точно знать, как взаимодействовать с объектом «Инвентарь»:

...
java.util.List inventory = new ArrayList(); 
...
//later in our program, we can interact with inventory
//  with any of methods on the list interface (because ArrayList "implements" List)
inventory.add(new Furniture("chair"));
inventory.add(new Appliance("refrigerator"));
inventory.add(new Food("ice cream"));
...

Итак, в приведенном выше примере инвентаризация - это переменная, которая содержит экземпляр типа ArrayList. Поскольку определение класса ArrayList реализует интерфейс «Список», все экземпляры типа ArrayList должны подчиняться контракту, определенному в интерфейсе «Список». Другими словами, мы могли бы создать inventory так же легко, как и LinkedList (вместо ArrayList), например:

java.util.List inventory = new LinkedList();

Не забудьте думать об интерфейсе как о контракте, который выставляет определенный набор действий, которые должны быть предварительно сформированы. Поскольку LinkedList и ArrayList реализуют интерфейс «Список», они оба обязаны по контракту реализовать все методы в интерфейсе «Список».

Самое замечательное в этом то, что любой код, который заинтересован в использовании нашей переменной «инвентаризации», не дает дерьма о как «добавить», «удалить» или «итератор» действия реализованы. Все, что им важно - переменная «инвентарь» подчиняется интерфейсу «Список».

Другими словами, LinkedList реализует метод add, немного отличающийся от ArrayList. Но это не имеет значения для любого кода, который хочет использовать нашу переменную «инвентарь».

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

java.util.List inventory = new CrazyMoonList();

Весь остальной код, использующий инвентарь, может оставаться таким же, потому что CrazyMoonList гарантированно предоставит «добавить», «удалить» и т. Д.

Надеюсь, это поможет прояснить понятия!

0 голосов
/ 06 января 2011

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

//defines a simple class describing all types of fruit
public class Fruit {
    //insert fields here...

    Fruit(){//constructor method
        //insert constructor code here... 
    }

    //insert class methods here.... 
}

Когда мы создаем экземпляр этого класса как объекта, мы должны дать компилятору знать, каким типом объекта он будет. В этом случае наш объект будет иметь тип Fruit.

//The initialisation might look something like this. 
Fruit myFruit = new Fruit(); 

Предыдущая строка кода указывает компилятору создать новый объект типа Fruit.

Таким образом, в простых терминах «класс» определяет характеристики объекта (его данные), где «тип» относится к типу объекта, на который мы смотрим, когда он был создан, будь то Fruit, Car или Стол письменный!

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

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

...