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

抽象类vs.接口vs.混合

  •  98
  • Sasha Chedygov  · 技术社区  · 17 年前

    抽象类 , 接口 混入

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

    抽象类

    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());
        }
    }
    

    如果一个子类不覆盖未实现的方法,它也是一个抽象类。

    interface 关键字。这些或多或少是一个没有实现的抽象类。(常量、嵌套类、显式实现和访问修饰符都很棘手,我不打算深入探讨。)虽然关于“无实现”的部分在Java中不再适用,但他们添加了默认方法。这 接口

    回到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());
        }
    }
    

    Deadly Diamond of Death Problem 在允许多重继承的语言中发现(如果处理得当,这并不是那么致命)。

    混入

    behavioral reuse , more flexible more powerful 接口 混音器不是接口。 它们是多重继承。有一个更漂亮的名字。

    这并不是说混音不好。多重继承并不坏。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());
        }
    }
    

    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    16 年前

    一般来说:

    接口 是一个指定操作的合约,但没有任何实现。一些语言(Java、C#)已经内置了对接口的支持,而在其他语言中,“接口”描述了一种约定,就像C++中的纯虚拟类一样。

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

    A.

    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 .

    HibernateDaoSupport .

        3
  •  6
  •   Ran    16 年前

    1. 将不相关的类与“ has a “能力。

    抽象类:

    1. is a

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

    我用一个小例子来结束分歧。

    Animal 可以是抽象类。 Cat Dog 是一个 “关系。

    是一个

    是一个 动物。

    can 实施 Bark 有a 吠叫的能力。

    实施 Hunt 界面。然后猫 有a 狩猎能力。

    ,谁是 not Animal ,可以实现 狩猎 界面。然后男人 有a 狩猎能力。

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

    混合物:

    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?

        4
  •  3
  •   Jon Erickson    17 年前

    引用Java和给出的抽象类示例来提供mixin是有误导性的。 首先,Java默认不支持“混入”。在Java术语中,抽象类和Mixin变得令人困惑。

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

    寻找Scala和Ruby等语言来适当实现“混入”的概念

        5
  •  3
  •   Community Mohan Dere    9 年前

    Joshua Bloch在他有效的Java书中很好地定义了“Mixin”的含义。摘自同一本书:

    " mixin是一种类型 一些可选行为。例如,Comparable是一个混入接口 可比对象。这样的接口被称为混入,因为它允许 "

        6
  •  1
  •   Beatles1692    17 年前

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

        7
  •  1
  •   Sumit Sengar    12 年前

    抽象类不能被实例化,因此它们的构造函数不应该是公共的。]

        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;
        }
    

    }

    接口是类要实现的契约。它只声明实现类成员的签名,它本身没有实现。我们通常使用接口来实现多态性,并解耦依赖类。

    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
    }
    }