代码之家  ›  专栏  ›  技术社区  ›  Sasha Chedygov

抽象类、接口和混合函数

  •  57
  • Sasha Chedygov  · 技术社区  · 16 年前

    有人能给我解释一下 抽象类 , 界面 混入 ?我以前在代码中使用过每种方法,但我不知道技术上的区别。

    7 回复  |  直到 16 年前
        1
  •  63
  •   Michael    7 年前

    抽象类

    抽象类是一个不是为实例化而设计的类。抽象类不能有任何实现、某些实现或所有实现。抽象类的设计允许其子类共享公共(默认)实现。抽象类的(伪代码)示例如下

    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 关键字。这些或多或少是一个没有实现的抽象类。(对于常量、嵌套类、显式实现和访问修饰符我都不太理解。)虽然“爪哇中没有实现”的部分不再适合,但他们添加了默认方法。这个 界面 关键字可以看作是接口概念的一种具体化。

    返回到形状示例

    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语言使用接口作为解决方案。 Deadly Diamond of Death Problem 在允许多重继承的语言中发现(如果处理得当,这并不是致命的)。

    混合蛋白

    混合(有时称为特征)允许抽象类的多重继承。MIXIN不具有多重继承的可怕关联(由于C++疯狂),所以人们更容易使用它们。他们有同样致命的致命钻石,但是支持他们的语言有比C++更优雅的减轻它的方法,所以他们被认为是更好的。

    混音器被称为与 behavioral reuse , more flexible 接口,以及 more powerful 接口。你会注意到所有这些都有这个术语 界面 其中,引用了Java和C语言关键字。 混音器不是接口。 它们是多重继承。有一个更漂亮的名字。

    这并不是说混音不好。多重继承也不错。C++解决多重继承的方式是每个人都在努力解决的问题。

    关于疲惫的老样子的例子

    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版开始就支持mixin。您可以使用接口上的扩展方法来实现这一点。下面是带real(!)的形状示例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());
            }
        }
    }
    
        2
  •  20
  •   Paul Morie    15 年前

    一般来说:

    界面 是一个指定操作的合同,但没有任何实现。一些语言(Java,C语言)已经为接口提供了支持,而在其他的“接口”中描述了一个类似于C++中的纯虚拟类的约定。

    抽象类 是一个类,它指定至少一个没有实现的操作。抽象类还可以提供其实现的某些部分。同样,一些语言也支持将类标记为抽象的,而在其他语言中则是隐式的。例如,在C++中,定义纯虚方法的类是抽象的。

    混合蛋白 是一个类,其设计目的是使某些功能在子类中的实现更容易,但它本身并没有设计为可供使用。例如,假设我们有一个用于处理请求的对象的接口

    interface RequestHandler {
      void handleRequest(Request request);
    }
    

    也许通过将请求累积到预定的数目,然后刷新缓冲区来缓冲请求是有用的。我们可以使用 混合蛋白 不指定刷新行为:

    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 .

        3
  •  6
  •   Ran    15 年前

    引用Java和给定的抽象类实例来提供MIXIN是有误导性的。 首先,Java不支持默认的“MIXIN”。在Java术语中,抽象类和混合集变得混乱。

    mixin是一个类可以实现的类型,除了它的“主类型”之外,它还表示它提供了一些可选的行为。用Java术语来说,一个例子就是实现可序列化的业务值对象。

    Josh Bloch说,“抽象类不能用来定义MIXIN,因为一个类不能有不止一个父代”(记住Java只允许一个“扩展”候选)。

    寻找类似scala和ruby的语言来适当实现“mixin”的概念。

        4
  •  3
  •   Jon Erickson    16 年前

    抽象类基本上是一个带有一些具体实现的接口。接口只是一个没有实现细节的契约。

    如果要创建涉及实现抽象类的所有对象的公共功能,则可以使用和抽象类。保持OOP的干燥(不要重复)原则。

        5
  •  3
  •   Community CDub    8 年前

    因为很多人已经解释了定义和用法,所以我只想强调一些重要的点

    接口:

    1. 定义一个契约(最好是无状态的-我的意思是没有变量)
    2. 将无关类与“”链接 has a “能力。
    3. 声明公共常量变量(不可变状态)

    抽象类:

    1. 在几个密切相关的类之间共享代码。它确立了 is a “关系”。

    2. 在相关类之间共享公共状态(可以在具体类中修改状态)

    我用一个小例子来结束这个差异。

    Animal 可以是抽象类。 Cat Dog ,扩展此抽象类建立“ 是一个 “关系”。

    是一个 动物

    是一个 动物。

    can 实施 Bark 接口。然后狗 有一个 吠叫的能力。

    可以 实施 Hunt 接口。然后猫 有一个 狩猎能力。

    ,谁是 not Animal 可以实现 亨特 接口。然后人 有一个 狩猎能力。

    人和动物(猫/狗)是不相关的。但Hunt接口可以为无关实体提供相同的功能。

    Mixin:

    1. 如果你想要两者的混合物 abstract class interface . 当您想要在许多不相关的类上强制执行一个新契约时尤其有用,其中一些类必须重新定义新的行为,而其中一些类应该坚持通用的实现。在mixin中添加公共实现,并允许其他类根据需要重新定义契约方法。

    如果我想声明一个抽象类,我将遵循这两种方法之一。

    1. 将所有抽象方法移到 界面 我的抽象类实现了这个接口。

      interface IHunt{
          public void doHunting();
      }
      abstract class Animal implements IHunt{
      
      }
      class Cat extends Animal{
          public void doHunting(){}
      }
      

    相关SE问题:

    What is the difference between an interface and abstract class?

        6
  •  1
  •   Beatles1692    16 年前

    抽象类是一个不是所有成员都实现的类,它们留给继承者实现,它强制继承者实现其抽象成员。 抽象类不能被实例化,因此它们的构造函数不应该是公共的。]

    下面是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
    }
    }
    
        7
  •  1
  •   Sumit Sengar    11 年前

    “混合”的含义在Joshua Bloch的JavaBook书中得到了很好的定义。同一本书的摘录:

    混合蛋白是一种类型 类除了可以实现它的__primary type_157;之外,还可以实现它来声明它提供 一些可选行为。例如,Comparable是一个 允许类声明其实例是相对于其他实例相互排序的 可比对象。这样的接口称为mixin,因为它允许 可选功能将__与__混合到__类型的主要功能中。