Abstract classes vs. interfaces vs. mixins

2019-03-07 18:38发布

问题:

Could someone please explain to me the differences between abstract classes, interfaces, and mixins? I've used each before in my code but I don't know the technical differences.

回答1:

Abstract Class

An abstract class is a class that is not designed to be instantiated. Abstract classes can have no implementation, some implementation, or all implementation. Abstract classes are designed to allow its subclasses share a common (default) implementation. A (pseudocoded) example of an abstract class would be something like this

abstract class Shape {
    def abstract area();  // abstract (unimplemented method)
    def outline_width() = { return 1; }  // default implementation
}

A subclass might look like

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
}

Possible usage

def main() = {
    Shape[] shapes = { new Rectangle(), new Oval() };
    foreach (s in shapes) {
        print("area: " + s.area() + ", outline width: " + s.outline_width());
    }
}

If a subclass does not override unimplemented methods, it is also an abstract class.

Interface

In general computer science terms, an interface is the parts of a program exposed to a client. Public classes and members are examples of interfaces.

Java and C# have a special interface keyword. These are more or less an abstract class with no implementation. (There's trickiness about constants, nested classes, explicit implementation, and access modifiers that I'm not going to get into.) Though the part about "no implementation" doesn't fit any more in Java, they added default methods. The interface keyword can be seen as a reification of the interface concept.

Going back to the Shape example

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 and C# do not allow multiple inheritance of classes with implementation, but they do allow multiple interface implementation. Java and C# use interfaces as a workaround to the Deadly Diamond of Death Problem found in languages that allow multiple inheritance (which isn't really that deadly, if properly handled).

Mixin

A mixin (sometimes called a trait) allows multiple inheritance of abstract classes. Mixins don't have the scary association that multiple inheritance has (due to C++ craziness), so people are more comfortable using them. They have the same exact Deadly Diamond of Death Problem, but languages that support them have more elegant ways of mitigating it than C++ has, so they're perceived as better.

Mixins are hailed as interfaces with behavioral reuse, more flexible interfaces, and more powerful interfaces. You will notice all these have the term interface in them, referring to the Java and C# keyword. Mixins are not interfaces. They are multiple inheritance. With a prettier name.

This is not to say that mixins are bad. Multiple inheritance isn't bad. The way C++ resolves multiple inheritance is what everyone gets all worked up about.

On to the tired, old Shape example

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

You will notice there is no difference between this and the abstract class example.

One extra tidbit is that C# has supported mixins since version 3.0. You can do it with extension methods on interfaces. Here's the Shape example with real(!) C# code mixin style

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:

In general:

An interface is a contract specifying operations, but without any implementation. Some languages (Java, C#) have baked-in support for interfaces, and in others 'interface' describes a convention like a pure virtual class in C++.

An abstract class is a class which specifies at least one operation without an implementation. Abstract classes can also provide some parts of their implementation. Again, some languages have baked-in support for marking classes as abstract and it is implicit in others. For example, in C++ a class which defines a pure virtual method is abstract.

A mixin is a class which is designed to make implementation of certain functionality easier in subclasses, but which is not designed to be used by itself. For example, say that we have an interface for an object that handles requests

interface RequestHandler {
  void handleRequest(Request request);
}

Perhaps it would be useful to buffer the requests by accumulating them until we have some predetermined number and then flushing the buffer. We can implement the buffering functionality with a mixin without specifying the flush behavior:

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

This way, it's easy for us to write a request handler that writes requests to disk, calls a web service, etc. without rewriting the buffering functionality each time. These request handlers can simply extend BufferedRequestHandlerMixin and implement flushBuffer.

Another good example of a mixin is one of the many support classes in Spring, viz. HibernateDaoSupport.



回答3:

Reference to Java and given example of Abstract class to provide mixin is misleading. First of all, Java does not support "mixins" by default. In Java terms abstract class and Mixins become confusing.

A mixin is a type that a class can implement in addition to its "primary type" to indicate that it provides some optional behavior. To speak in Java terms, one example would be your business value object implementing Serializable.

Josh Bloch says - "Abstract classes can not be used to define mixins - since a class can not have more than one parent" ( Remember Java allows only one "extends" candidate)

Look for languages like Scala and Ruby for appropriate implementation of the notion of "mixin"



回答4:

Basically an abstract class is an interface with some concrete implementation. An interface is just a contract that has no implementation detail.

You would use and abstract class if you want to create common functionality amoung all of the objects that implement the abstract class. Keeping with the DRY (Don't Repeat Yourself) principle of OOP.



回答5:

Since many of guys have explained about the definitions and usage, I would like to highlight only important points

Interface:

  1. To define a contract ( preferably stateless - I mean no variables )
  2. To link unrelated classes with "has a" capabilities.
  3. To declare public constant variables (immutable state)

Abstract class:

  1. Share code among several closely related classes. It establishes "is a" relation.

  2. Share common state among related classes ( state can be modified in concrete classes)

I am closing the difference with a small example.

Animal can be an abstract class. Cat and Dog, extending this abstract class establishes "is a" relation.

Cat is a Animal

Dog is a Animal.

Dog can implement Bark interface. Then Dog has a capability of Barking.

Cat can implement Hunt interface. Then Cat has a capability of Hunting.

Man, who is not Animal, can implement Hunt interface. Then Man has a capability of Hunting.

Man and Animal (Cat/Dog) are unrelated. But Hunt interface can provide same capability to unrelated entities.

Mixin:

  1. If you want a mixture of both abstract class and interface. Especially useful when you want to force a new contract on many unrelated classes where some of them have to re-define new behaviour and some of them should stick to common implementation. Add common implementation in Mixin and allow other classes to re-define the contract methods if needed

If I want to declare an abstract class, I will follow one of these two approaches.

  1. Move all abstract methods to interface and my abstract class implements that interface.

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

Related SE question :

What is the difference between an interface and abstract class?



回答6:

An abstract class is a class that not all of its members are implemented ,they are left for the inheritors to be implemented.It forces its inheritors to implement its abstract members. Abstract classes can't be instantiated and thus their constructors shouldn't be public.]

Here's an example in 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;
    }

}

An interface is a contract to be implemented by a class.It just declare the signature of the members of an implementing class and it has no implementation itself.We usually use interfaces to implement polymorphism,and to decouple dependent classes.

Here's an example in 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:

The meaning of 'Mixin' is excellently defined by Joshua Bloch in his effective Java book. An excerpt from the same book:

"mixin is a type that a class can implement in addition to its “primary type” to declare that it provides some optional behavior. For example, Comparable is a mixin interface that allows a class to declare that its instances are ordered with respect to other mutually comparable objects. Such an interface is called a mixin because it allows the optional functionality to be “mixed in” to the type’s primary functionality."