The beauty of design patterns learning (six): the difference between an interface vs abstract class? How to simulate normal class abstract classes and interfaces?

In object-oriented programming, abstract classes and interfaces are two grammar concepts are often used, are the four characteristics of object-oriented, and a lot of design patterns, design, programming basic design principles to achieve. For example, we can use the interface to implement object-oriented abstraction features, characteristics and polymorphism-based interface rather than the realization of the design principles, the use of abstract classes inherit properties and templates to implement object-oriented design patterns and so on.

However, not all object-oriented programming languages support these two concepts of grammar, for example, C++this programming language only supports abstract classes, interfaces are not supported; and like Pythondynamic programming languages such, neither supports abstract classes, nor does it support interface. Although some programming language does not provide ready-made syntax to support interfaces and abstract classes, we can still achieve some means to simulate these two grammatical concepts.

The syntax of these two concepts are often used not only at work, often mentioned in the interview. For example, "the difference between abstract classes and interfaces What? When to use an interface? When to use abstract class? Abstract class and interface What is the meaning of existence? What program can solve the problem?" And so on.

What are abstract classes and interfaces? What's the Difference?

Different programming languages ​​may be some differences in the way the definition of interfaces and abstract classes, but the difference is not great.

First look at this programming language, how we define abstract class.Java

The following code is an abstract class typical usage scenario (template design mode). LoggerIs a log of abstract classes, FileLoggerand MessageQueueLoggerinheritance Logger, respectively, to achieve two different logging mode: the log files and log into the message queue. FileLoggerAnd MessageQueueLoggertwo subclasses reuse the parent class Loggerof name, enabled, minPermittedLevelproperties and log()methods, but because of the two different sub-classes to write the log of the way, but they rewrote their parent class doLog()method.

// 抽象类
public abstract class Logger {
  private String name;
  private boolean enabled;
  private Level minPermittedLevel;

  public Logger(String name, boolean enabled, Level minPermittedLevel) {
    this.name = name;
    this.enabled = enabled;
    this.minPermittedLevel = minPermittedLevel;
  }
  
  public void log(Level level, String message) {
    boolean loggable = enabled && (minPermittedLevel.intValue() <= level.intValue());
    if (!loggable) return;
    doLog(level, message);
  }
  
  protected abstract void doLog(Level level, String message);
}
// 抽象类的子类:输出日志到文件
public class FileLogger extends Logger {
  private Writer fileWriter;

  public FileLogger(String name, boolean enabled,
    Level minPermittedLevel, String filepath) {
    super(name, enabled, minPermittedLevel);
    this.writer = new FileWriter(filepath); 
  }
  
  @Override
  public void doLog(Level level, String mesage) {
    // 格式化level和message,输出到日志文件
    fileWriter.write(...);
  }
}
// 抽象类的子类: 输出日志到消息中间件(比如kafka)
public class MessageQueueLogger extends Logger {
  private MessageQueueClient msgQueueClient;
  
  public MessageQueueLogger(String name, boolean enabled,
    Level minPermittedLevel, MessageQueueClient msgQueueClient) {
    super(name, enabled, minPermittedLevel);
    this.msgQueueClient = msgQueueClient;
  }
  
  @Override
  protected void doLog(Level level, String mesage) {
    // 格式化level和message,输出到消息中间件
    msgQueueClient.send(...);
  }
}复制代码

With this look at the example above, the abstract class What features.

  • Abstract classes are not allowed to be instantiated, can only be inherited. In other words, you can not be newthe object of an abstract class out ( Logger logger = new Logger(…);will report compilation errors).
  • An abstract class may contain attributes and methods. The method may be implemented contain code (for example, Loggerin log()the method), or may not contain code implementation (such as Loggerin doLog()a method). The method does not contain the code that implements the abstract method is called.
  • Subclass inherits an abstract class, all the abstract methods abstract class must implement. Corresponds to the example code is that all successor Loggersubclasses of the abstract class must override doLog()method.

Then look at, in this programming language, how we define the interface.Java

// 接口
public interface Filter {
  void doFilter(RpcRequest req) throws RpcException;
}
// 接口实现类:鉴权过滤器
public class AuthencationFilter implements Filter {
  @Override
  public void doFilter(RpcRequest req) throws RpcException {
    //...鉴权逻辑..
  }
}
// 接口实现类:限流过滤器
public class RateLimitFilter implements Filter {
  @Override
  public void doFilter(RpcRequest req) throws RpcException {
    //...限流逻辑...
  }
}
// 过滤器使用demo
public class Application {
  // filters.add(new AuthencationFilter());
  // filters.add(new RateLimitFilter());
  private List<Filter> filters = new ArrayList<>();
  
  public void handleRpcRequest(RpcRequest req) {
    try {
      for (Filter filter : fitlers) {
        filter.doFilter(req);
      }
    } catch(RpcException e) {
      // ...处理过滤结果...
    }
    // ...省略其他处理逻辑...
  }
}复制代码

The code above is a typical usage scenario interface. By Javathe interfacedefinition of a keyword Filterinterface. AuthencationFilterAnd RateLimitFiltertwo interface implementation class, were realized to RPCrequest authentication and limiting filtering.

The code is very simple. Then look at the combination of the code, which has characteristics of the interface.

  • Interfaces can not contain attributes (that is, member variables).
  • Interface can be declared only methods, the method can not contain code.
  • When class implements an interface, all methods declared in the interface must be implemented.

Comparative syntactically properties, both of which have a relatively large difference, such as abstract classes can be defined to achieve the properties, methods, and interface properties can not be defined, the method comprising the code can not be achieved and the like. In addition to grammatical features, from a design perspective, there are two relatively big difference.

An abstract class is actually a class, but is a special class, this class can not be instantiated as an object, only inherited by subclasses. We know that the inheritance relationship is a is-arelationship, since that belong to the class abstract class, also represents one is-arelationship. Abstract class with respect to the is-arelationship, the interface shows a has-arelationship, represent a certain function. For the interface, there is a more vivid name for that agreement ( contract).

Abstract classes and interfaces can solve any programming problem?

Why do we need an abstract class? It can solve any programming problem?

An abstract class is a code reuse born. A plurality of subclasses inherit attributes and methods defined in the abstract class, subclass avoid, rewriting the same code.

However, since the succession itself can achieve the purpose of code reuse, inheritance and does not require that the parent class must be abstract class, then we do not use an abstract class, it can still be achieved inherit and reuse. From this perspective, we do not need an abstract class that looks like syntax Yeah. That abstract class in addition to solve the problem of code reuse, what other meaning of existence it?

Or that example of the printing log before the take. We first of the above code to do the next transformation. After the code transformation, Loggerno longer is an abstract class, just an ordinary parent, deleted Loggerin log(), doLog()method, add the isLoggable()method. FileLoggerAnd MessageQueueLoggerstill inherit Loggerthe parent class, in order to achieve the purpose of code reuse. Specific code as follows:

// 父类:非抽象类,就是普通的类. 删除了log(),doLog(),新增了isLoggable().
public class Logger {
  private String name;
  private boolean enabled;
  private Level minPermittedLevel;

  public Logger(String name, boolean enabled, Level minPermittedLevel) {
    //...构造函数不变,代码省略...
  }

  protected boolean isLoggable() {
    boolean loggable = enabled && (minPermittedLevel.intValue() <= level.intValue());
    return loggable;
  }
}
// 子类:输出日志到文件
public class FileLogger extends Logger {
  private Writer fileWriter;

  public FileLogger(String name, boolean enabled,
    Level minPermittedLevel, String filepath) {
    //...构造函数不变,代码省略...
  }
  
  public void log(Level level, String mesage) {
    if (!isLoggable()) return;
    // 格式化level和message,输出到日志文件
    fileWriter.write(...);
  }
}
// 子类: 输出日志到消息中间件(比如kafka)
public class MessageQueueLogger extends Logger {
  private MessageQueueClient msgQueueClient;
  
  public MessageQueueLogger(String name, boolean enabled,
    Level minPermittedLevel, MessageQueueClient msgQueueClient) {
    //...构造函数不变,代码省略...
  }
  
  public void log(Level level, String mesage) {
    if (!isLoggable()) return;
    // 格式化level和message,输出到消息中间件
    msgQueueClient.send(...);
  }
}复制代码

Although this design ideas to achieve the purpose of code reuse, but can not use the multi-state characteristics. Write code like the following, compile-time error occurs, because Loggernot defined log()method.

Logger logger = new FileLogger("access-log", true, Level.WARN, "/users/muchen/access.log");
logger.log(Level.ERROR, "This is a test log message.");复制代码

You might say, to solve this problem is very simple ah. In the Loggerparent class, define an empty log()way for subclasses override the parent class log()method, implement the logic of its own logging, can not it do?

public class Logger {
  // ...省略部分代码...
  public void log(Level level, String mesage) { // do nothing... }
}
public class FileLogger extends Logger {
  // ...省略部分代码...
  @Override
  public void log(Level level, String mesage) {
    if (!isLoggable()) return;
    // 格式化level和message,输出到日志文件
    fileWriter.write(...);
  }
}
public class MessageQueueLogger extends Logger {
  // ...省略部分代码...
  @Override
  public void log(Level level, String mesage) {
    if (!isLoggable()) return;
    // 格式化level和message,输出到消息中间件
    msgQueueClient.send(...);
  }
}复制代码

This design concept can be used, however, it apparently did not realize before by elegant abstract ideas. Why do you say? The main reasons are as follows.

  • In the Loggermethod defined in an empty, it will affect the readability of the code. If we are not familiar with the Loggerunderlying design philosophy, not how to force code comments, we read in Loggerthe time code, it is possible to define how an empty log()method and confused, and need to see Logger, FileLogger, MessageQueueLoggerinheritance relationships, in order to understand it plan for design.
  • When creating a new subclass inherits Loggerthe parent class, we may forget to re-implement log()methods. Based on design ideas before an abstract class, the compiler will enforce subclass overrides log()the method, otherwise it will report compilation errors. You might say, since I want to define a new Loggersubclass will forget how to re-implement log()way to do that? Our example is relatively simple, Loggernot much in the way, and few lines of code. However, if Loggerthere are hundreds of lines, there are nmore than method, unless you Loggerdesign are very familiar with, or forget to re-implement log()method, it is not impossible.
  • LoggerCan be instantiated, in other words, we can be newa Loggerout and call an empty log()method. It also increases the risk of misuse of the class. Of course, this problem can be solved by setting the private constructor method. But obviously it did not come through elegant abstract class.

Why Interface? It can solve any programming problem?

More abstract class for code reuse, and the interface is more focused on decoupling. Interface is an abstract of the act, the equivalent of a set of agreements or contracts, you can think of an analogy about the APIinterface. The caller only need to focus on the abstract interface, do not need to know the specific implementation, the specific implementation code transparent to the caller. Interface conventions and phase separation can be reduced coupling between the code, the code to improve scalability.

In fact, the interface is a broader class of applications than the abstract, is more important points. For example, often referred to "interface-based programming rather than achieve" is one almost every day will be used, and can greatly improve the flexibility of code, design scalability.

How to simulate two abstract classes and interfaces grammar concepts?

In the previous example cited, the use of Javathe interface syntax implements a Filterfilter. However, if you are familiar with C++this programming language, you might say, C++only an abstract class, and there is no interface, that from the point of view of code to achieve, it is not can not be achieved Filterdesign ideas of it?

First recall the definition of the interface: The interface is not a member variable, only the method declaration, there is no way to achieve, all the interface implementation class must implement the interface methods. As long as these points, from a design point of view, we can call it the interface. In fact, to meet the interface of these characteristics syntax is not difficult. In the following this C++code, use the abstract class interface to an analog (hereinafter, this code is actually a piece of code in the policy model).

class Strategy { // 用抽象类模拟接口
  public:
    ~Strategy();
    virtual void algorithm()=0;
  protected:
    Strategy();
};复制代码

An abstract class Strategydoes not define any attribute, and all methods are declared as virtualtype (equivalent to Javathe abstractkeywords), so that all can not have a method implemented in code and all inherited abstract class subclass must implement these methods . From the grammatical characteristics of view, this is equivalent to an abstract class interface.

In Python, Rubythese dynamic languages, not only did the concept of interface, there is no similar abstract, virtualthis keyword to define an abstract class, then how to achieve the above mentioned Filter, Loggerthe design ideas of it? In fact, in addition to the abstract class analog interface, it can also be used to simulate normal class interfaces. Specific Javacode implementation shown below.

public class MockInteface {
  protected MockInteface() {}
  public void funcA() {
    throw new MethodUnSupportedException();
  }
}复制代码

Method in class must contain realize that this does not meet the definition of the interface. However, we can let the class method throws MethodUnSupportedExceptionan exception, to simulate the interface does not contain, and can force the subclass inherits the parent class, all the parent class to take the initiative to achieve, otherwise it will throw at runtime abnormal. So what this class is instantiated to avoid it? Is actually quite simple, we only need to declare the constructor of the class to protectedaccess it.

How do you decide the abstract classes or interfaces?

In fact, the criterion of judgment is very simple. If we want to represent one is-arelationship, and to solve the problem of code reuse, we use an abstract class; if we want to represent one has-arelationship, and to solve the problem rather than the abstract code reuse, and then we can use interface.

From the point of view of the inheritance hierarchy class, abstract class is a bottom-up design ideas, first subclass of code duplication, and then abstracted into the upper parent class (that is, an abstract class). The interface to the contrary, it is a top-down design ideas. We are programming, are generally the first design of the interface, go to consider the implementation.

RECAP

1. Syntax characteristics of abstract classes and interfaces

Abstract classes are not allowed to be instantiated, can only be inherited. It can contain attributes and methods. The method comprising the code may be implemented, or may not contain code. The method does not contain the code that implements the abstract method is called. Subclass inherits an abstract class, all the abstract methods abstract class must implement. Interfaces can not contain attributes, can only declarative approach, the method can not contain code. When class implements an interface, all methods declared in the interface must be implemented.

2. The existence of abstract classes and interfaces significance

Abstract class is an abstract of the member variables and methods, is a is-arelationship, in order to solve the problem of code reuse. Only the interface is an abstract method, a has-arelationship, represents a group having behavioral characteristics, to solve the problem of decoupling, the isolation interface and the specific implementation, improved spreading code.

3. The difference between the application scenario of abstract classes and interfaces

When to use abstract class? When to use an interface? In fact, the criterion of judgment is very simple. If you want to represent one is-arelationship, and code reuse in order to solve the problem, we will use abstract class; if you want to represent one has-arelationship, and to solve abstract problems rather than code reuse, then we use the interface.

Think

  • Interfaces and abstract classes are two concepts frequently asked in the interview. If you let the interviewer talk about interfaces and abstract classes, how would you answer it?

Reference: the difference between interfaces vs abstract classes? How to simulate normal class abstract classes and interfaces?

This article from the blog article multiple platforms OpenWrite release!

For more information, please click on my blog Mu Chen

Guess you like

Origin juejin.im/post/5de11f51f265da05ea763933