What is the purpose of abstract classes?

2020-02-25 08:25发布

问题:

I am trying to learn OOP in PHP, and I have some confusion about interfaces and abstract classes. They both contain no implementations, only definitions, and should be implemented through their sub-classes. What part of abstract classes clearly distinguishes them from interfaces? Also, due to their apparent similarities, based on what reasons should I decide to use one over the other?

回答1:

It is possible to create abstract classes that contain concrete members, such as methods or properties. You still can't instantiate the abstract class directly, but any instantiated sub-classes can benefit from implemented members defined in the abstract class.

An interface, by comparison, never contains any implementation logic. It is down to each implementing class to provide the implementation of all members defined in the interface.

In terms of how I view the differences, a sub-class of an abstract is-a class of that type. e.g. Dog is an Animal. I see an interface as a does-a relationship. e.g. ICanDisplayImages tells me that the implementing class can display images, but tells me nothing about what the class actually represents.



回答2:

An abstract class forms an is-a relationship between itself and the subclass, while an interface creates a follows-a relationship. As such, abstract classes are much more concrete than interfaces and they may also contain concrete implementations (e.g. Template methods) while an interface defines a contractual set of methods an implementing class must follow. This is a much higher level of abstraction as the implementing class must not necessarily be of the abstract class. Use it to standardize your API.

Related questions: https://stackoverflow.com/search?q=abstract+vs+interface



回答3:

Beyond the OOP philosophy described in other answers, I think the major use of abstract class is kind of a skeleton.

It's usefull when you design an application, or work with a team, because you have a base code to work with and extends it's close to interface but with a more advanced workflow.



回答4:

They both contain no implementations..

Abstract class can implements all or only part of the methods. But the main philosophy - is extend existing abstract class by to add a new methods in child classes (that extend a basic functionality).

In a child class you can extend only one class (abstract class). Abstract class define functionality that you must implement or just extends by other methods in child classes.

Interfaces are use to define the class behaviors. You can implement more than one interface(and say my child-class must do this,this and this thigs!), but you can extend only one abstract class.



回答5:

The main difference between an abstract class and an interface is that an interface defines common behaviors, where an abstract class is a foundation class for inheritance. In other words, an abstract class defines some core set of methods and properties that subclasses might share. Consider a class that defines a License. All licenses have an id number of some type and are issued to some individual or group. A license class might be extended by a Driver's License class, a Bicycle License class, and Hunting License class, and so on. The main reason one would make the License class abstract is because it defines an abstract idea of a license. There is no such thing as a license, so by declaring the class abstract, it cannot be instantiated.
An interface, on the other hand, does not define an object at all. It defines method signatures. Any non-abstract class that implements an interface must provide an implementation for all of the methods in the interface. The advantage here is the method provides a common interface across different types of objects, e.g. compareTo() looks the same when used with Strings or any other object.



回答6:

An abstract class can contain method implementations if the method is not defined as abstract. If the method is defined as abstract, it does not contain an implementation, but it needs to be implemented by its inheritors. An abstract class cannot be instantiated, but only inherited from, for the inheritor to allow it to use its behaviors.

An interface only defines method signatures and any class inheriting from it must implement all methods contained in the interface.



回答7:

Usually interfaces are used to define contracts, so you get type checking. There is also a programming style called "programming against interfaces", which is a good idea. See the Dependency Inversion Principle:

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.

B. Abstractions should not depend upon details. Details should depend upon abstractions."

So if you define functions and methods, instead of type hinting against classes, you just hint against interfaces.

Here is an example. Let's say, you define interfaces for input streams and and output streams as follows:

interface OutputStream{
  write($string); // Writes a string to the output.
  close(); // Closes the output stream.
}

interface InputStream{
  read($length); // Reads at most $length characters.
  eof(); // TRUE, if the input stream is empty.
}

You could now create copy function or method, which copies the complete output of a stream to an input, without having any of them:

// 50 is just chosen randomly.
function copy(InputStream $input, OutputStream $output){
  while(!$input->eof()){
    $output->write($input->read(50));}}

Congratulations, your copy implementation now works for every combination of an input and output stream, without even implementing one.

Abstract classes, on the other hand, can be used to implement common functionality without having to implement a fully functional class.

Again, an example. Let's say, you want to have output streams. You want a method write($s), which writes a string to the output, and you want a method writeLine($s), which writes the string and an additional newline to the output. Then this would be appropriate:

abstract class AbstractOutputStream{
  public function writeLine($s){
    $this->write($s."\n");}}

Concrete output streams now could inherit from the abstract output stream, implement just write and get writeLine for free!