Абстрактный класс
Абстрактный класс - это класс, который не предназначен для реализации. Абстрактные классы могут не иметь никакой реализации, какой-либо реализации или всей реализации. Абстрактные классы предназначены для того, чтобы их подклассы имели общую (стандартную) реализацию. (Псевдокодированный) пример абстрактного класса будет выглядеть примерно так
abstract class Shape {
def abstract area(); // abstract (unimplemented method)
def outline_width() = { return 1; } // default implementation
}
Подкласс может выглядеть как
class Rectangle extends Shape {
int height = width = 5;
def override area() = { return height * width; } // implements abstract method
// no need to override outline_width(), but may do so if needed
}
Возможное использование
def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}
Если подкласс не переопределяет нереализованные методы, он также является абстрактным классом.
Интерфейс
В общих словах, касающихся компьютерных наук, интерфейс - это части программы, предоставляемые клиенту. Публичные классы и члены являются примерами интерфейсов.
Java и C # имеют специальное ключевое слово interface
. Это более или менее абстрактный класс без реализации. (Есть хитрость с константами, вложенными классами, явной реализацией и модификаторами доступа, в которые я не буду вдаваться.) Хотя часть об отсутствии реализации больше не подходит в Java, они добавили стандартные методы. Ключевое слово interface
можно рассматривать как воплощение концепции интерфейса.
Возвращаясь к примеру с Shape
interface Shape {
def area(); // implicitly abstract so no need for abstract keyword
def outline_width(); // cannot implement any methods
}
class Rectangle implements Shape {
int height = width = 5;
def override area() = { return height * width; }
def override outline_width() = { return 1; } // every method in interface must be implemented
}
def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}
Java и C # не допускают множественного наследования классов с реализацией, но они допускают множественную реализацию интерфейса. Java и C # используют интерфейсы в качестве обходного пути к проблеме Смертельный бриллиант смерти , обнаруживаемой в языках, которые допускают множественное наследование (что на самом деле не так уж смертельно при правильной обработке).
Mixin
Миксин (иногда называемый признаком) позволяет множественное наследование абстрактных классов. Миксины не имеют страшной связи, которая имеет множественное наследование (из-за сумасшествия C ++), поэтому людям удобнее ими пользоваться. У них точно такая же проблема Смертельного Бриллианта Смерти, но языки, которые их поддерживают, имеют более изящные способы ее смягчения, чем С ++, поэтому они воспринимаются как лучшие.
Миксины приветствуются как интерфейсы с поведенческим повторным использованием , более гибкими интерфейсами и более мощными интерфейсами. Вы заметите, что все они содержат термин interface
, относящийся к ключевым словам Java и C #. Миксины не являются интерфейсами. Они являются множественным наследованием. С красивым именем.
Это не значит, что миксины плохие. Многократное наследование не плохо. То, как C ++ разрешает множественное наследование, - это то, о чем все заботятся.
На старом, уставшем образце Shape
mixin Shape {
def abstract area();
def outline_width() = { return 1; }
}
class Rectangle with Shape {
int height = width = 5;
def override area() = { return height * width; }
}
def main() = {
Shape[] shapes = { new Rectangle(), new Oval() };
foreach (s in shapes) {
print("area: " + s.area() + ", outline width: " + s.outline_width());
}
}
Вы заметите, что нет разницы между этим и примером абстрактного класса.
Еще один важный момент: C # поддерживает миксины начиная с версии 3.0. Вы можете сделать это с помощью методов расширения на интерфейсах. Вот пример Shape с настоящим (!) Миксин-стилем кода C #
interface Shape
{
int Area();
}
static class ShapeExtensions
{
public static int OutlineWidth(this Shape s)
{
return 1;
}
}
class Rectangle : Shape
{
int height = 5;
int width = 5;
public int Area()
{
return height * width;
}
}
class Program
{
static void Main()
{
Shape[] shapes = new Shape[]{ new Rectangle(), new Oval() };
foreach (var s in shapes)
{
Console.Write("area: " + s.Area() + ", outline width: " + s.OutlineWidth());
}
}
}