有人可以向我解释抽象类,接口和mixins之间的区别吗?我以前在代码中都使用过它们,但是我不知道技术上的区别。
有人可以向我解释抽象类,接口和mixins之间的区别吗?我以前在代码中都使用过它们,但是我不知道技术上的区别。
Answers:
抽象类是一个不能实例化的类。抽象类可以没有任何实现,某些实现或全部实现。抽象类旨在允许其子类共享一个通用(默认)实现。一个抽象类的(伪编码)示例将是这样的
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
关键字可以被看作是所述接口概念的具体化。
回到形状示例
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(有时称为特征)允许抽象类的多重继承。Mixins没有多重继承所具有的可怕关联(由于C ++的疯狂),因此人们更习惯使用它们。它们具有完全相同的“致命问题致命钻石”,但是支持它们的语言比C ++具有更优雅的缓解方法,因此人们认为它们更好。
Mixins被称为具有行为重用,更灵活的接口和更强大的接口的接口。您会注意到所有这些都有其中的术语interface
,指的是Java和C#关键字。Mixins不是接口。它们是多重继承。用更漂亮的名字。
这并不是说mixins不好。多重继承也不错。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版开始就支持mixins。您可以使用接口上的扩展方法来实现。这是带有real(!)C#代码混合风格的Shape示例
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());
}
}
}
一般来说:
一个接口是指定操作的合同,但没有任何实现。某些语言(Java,C#)已经支持接口,而在其他语言中,“ interface”则描述了一种约定,例如C ++中的纯虚拟类。
一个抽象类是一类规定了没有一个实现至少一个操作。抽象类还可以提供其实现的某些部分。同样,某些语言已经支持将类标记为抽象,而在其他语言中则隐含支持。例如,在C ++中,定义纯虚拟方法的类是抽象的。
一个混入的,其目的是使执行特定功能的子类更容易,但它没有设计成单独使用的类。例如,假设我们有一个处理请求的对象的接口
interface RequestHandler {
void handleRequest(Request request);
}
通过累积请求直到达到预定数目,然后刷新缓冲区来缓冲请求可能会很有用。我们可以使用mixin实现缓冲功能,而无需指定刷新行为:
abstract class BufferedRequestHandlerMixin implements RequestHandler {
List<Request> buffer = new List<Request>();
void handleRequest(Request request) {
buffer.add(request);
if (buffer.size == BUFFER_FLUSH_SIZE) {
flushBuffer(buffer);
buffer.clear();
}
}
abstract void flushBuffer(List<Request> buffer);
}
这样,我们很容易编写一个请求处理程序,该请求处理程序将请求写入磁盘,调用Web服务等,而无需每次都重写缓冲功能。这些请求处理程序可以简单地扩展BufferedRequestHandlerMixin
和实现flushBuffer
。
mixin的另一个很好的例子是Spring中的许多支持类之一,即。HibernateDaoSupport。
引用Java和Abstract类的示例来提供mixin具有误导性。首先,Java默认情况下不支持“ mixins”。用Java术语来说,抽象类和Mixins变得令人困惑。
混合是一种类,除了其“主要类型”以外,还可以实现以指示它提供了一些可选的行为。用Java术语来说,一个示例是实现Serializable的业务价值对象。
乔什·布洛赫(Josh Bloch)说-“抽象类不能用于定义mixin-因为一个类不能有多个父类”(请记住Java仅允许一个“扩展”候选者)
寻找诸如Scala和Ruby之类的语言来适当实现“ mixin”概念
由于许多人已经解释了定义和用法,因此我只想强调重要点
接口:
has a
”功能链接不相关的类。抽象类:
在几个密切相关的类之间共享代码。建立“ is a
”关系。
在相关的类之间共享公共状态(状态可以在具体的类中修改)
我用一个小例子来解决这个问题。
Animal
可以是一个抽象类。Cat
并且Dog
,扩展此抽象类将建立“ is a
”关系。
猫 is a
动物
狗 is a
动物。
狗 can
实现Bark
接口。然后狗has a
的吠叫能力。
Cat can
工具Hunt
接口。然后猫has a
的狩猎能力。
男人,谁是not Animal
,可以实现Hunt
接口。然后人has a
的狩猎能力。
人与动物(猫/狗)无关。但是Hunt接口可以为不相关的实体提供相同的功能。
混合:
abstract class
和和interface
。当您想对许多不相关的类强制使用新合同时,这些类中的一些必须重新定义新的行为,而其中一些则应坚持通用实现,这一点尤其有用。在Mixin中添加通用实现,并允许其他类在需要时重新定义合同方法如果要声明一个抽象类,则将遵循以下两种方法之一。
将所有抽象方法移至interface
,我的抽象类将实现该接口。
interface IHunt{
public void doHunting();
}
abstract class Animal implements IHunt{
}
class Cat extends Animal{
public void doHunting(){}
}
相关SE问题:
基本上,抽象类是具有某些具体实现的接口。接口只是没有实现细节的合同。
如果要在实现抽象类的所有对象之间创建通用功能,则可以使用abstract类。遵守OOP的DRY(不要重复自己)原则。
抽象类是并非所有成员都实现的类,它们留给继承者来实现。它强制其继承者实现其抽象成员。抽象类无法实例化,因此其构造函数不应是公共的。]
这是C#中的示例:
public abstract class Employee
{
protected Employee(){}
public abstract double CalculateSalary(WorkingInfo workingInfo);//no implementation each type of employee should define its salary calculation method.
}
public class PartTimeEmployee:Employee
{
private double _workingRate;
public Employee(double workingRate)
{
_workingRate=workingRate;
}
public override double CalculateSalary(WorkingInfo workingInfo)
{
return workingInfo.Hours*_workingRate;
}
}
接口是要由类实现的协定。它仅声明实现类成员的签名,而本身没有实现。我们通常使用接口来实现多态性,并解耦依赖类。
这是C#中的示例:
public interface IShape
{
int X{get;}
int Y{get;}
void Draw();
}
public class Circle:IShape
{
public int X{get;set;}
public int Y{get;set;}
public void Draw()
{
//Draw a circle
}
}
public class Rectangle:IShape
{
public int X{get;set;}
public int Y{get;set;}
public void Draw()
{
//Draw a rectangle
}
}