抽象类可能有也可能没有抽象方法,但接口只有未实现的方法。那么,如果我的抽象类将其所有方法标记为抽象,那么使用接口的区别和优势是什么?
答案 0 :(得分:4)
接口和抽象
真正的使用能力可以在庞大的API中体现出来,其中包含大量的类,这些类遵循经过深思熟虑的灵活结构,以便将来编码。是否可能发生 - 您永远不知道代码是否会被扩展。接口仅用于语义原因。想象一下,您扩展了一个已弃用的API版本,并且可以编辑/更改/实现/更新/改进/扩展/修改代码以使其更新,无论原因是什么。如果你没有想到,你最终会感到沮丧。
可以在没有接口的情况下制作小型API,大多数人认为接口是不必要的。但是一旦它们变大,它们就会失去灵活性。他们为您提供课程合同,提醒您需要什么并保持概述。接口必须有公共方法,如果你有保护或私有方法,只需在实现接口的类的公共方法中返回它们。
就像你已经解释过的那样,接口需要实现特定的方法,抽象类不要求它,因为你最有可能扩展它们。可以重新定义方法,并且必须在子类中定义抽象方法。接口中提到的方法仅告诉您与接口签订合同的类必须具有这些定义的类。它可能是多个接口,你不会像使用抽象类那样继承它们。
这样思考
其中的逻辑是预测您计划构建的未来。无论是建筑,基础设施还是工厂的大规模生产。就像您对书签,书籍,文件夹中的图像等项目进行排序一样。因为您知道如果您没有对特定图像进行排序,则需要更长的时间才能找到它。抽象和接口的语义目的是类似的,尤其是在大型API中。
我将向您展示一个典型的API开始结构,其中包含简化的内容,其中接口和抽象类具有未来扩展的真实使用点。
/* Considering, this project will be widely expanded up to huge complexity.
This is a flexible base structure, for developers working in team. Imagine
there could be lots more variation of styles for certain purposes. */
// OOP STRUCT
// You might want to define multiple interfaces to separate the project
interface iString {
// These methods MUST be defined or else the developer receives an error
public function getContent();
public function description($desc);
}
/* Devs might want to add an additional method later on.
Traits are useful for quick use. (optional) */
trait desc {
private $desc;
public function description($desc) {
return $this->desc;
}
}
/* This is the base class for the content which requires a declaration
of methods being described in the interface */
class contents implements iString {
use desc; // use the method defined in a trait
private $str;
public function __construct($str) {
$this->str = $str;
}
public function getContent() {
return $this->str;
}
}
/* Or devs often consider abstract classes as the real base of the whole project/app.
Abstract classes allow the use of methods that can be modified/declared for further use in derived classes.
Interfaces can't do that */
abstract class stylize {
private $str;
// This typehint below makes sure that this value is assigned on interface
public function __construct(iString $str) {
$this->str = $str;
}
public function style() {
return $this->str->getContent();
}
abstract public function getContent();
}
// EXTENDED CLASSES
class bold extends stylize {
// Extended classes have to define abstract methods inherited from an abstract class. Non-abstract methods are not needed.
public function getContent() {
return "<strong>".parent::style()."</strong>";
}
}
class underline extends stylize {
public function getContent() {
return "<u>".parent::style()."</u>";
}
}
class upperCase extends stylize {
public function getContent() {
return strtoupper(parent::style());
}
}
// PROCEDUAL OUTPUT
// A tiny shortcut
$e = function($desc,$str) { echo $desc.": ".$str->getContent()."<br>"; };
// Content being used
$content = new contents('Hello World.');
$e("Normal",$content);
// Content being styled
$bold = new bold($content);
$underline = new underline($content);
$upper = new upperCase($content);
// Renders content with styles
$e("Bold",$bold);
$e("Underline",$underline);
$e("Uppercase",$upper);
<强>结论强>
应用文本内容的样式作为示例可能不够吸引人。但除此之外,它仍然是相同的 - 如果它做它应该做的事情,那么它就完成了。就像我将构建可扩展的eMail配置API作为CMS的模块一样。该结构在正确编码中具有语义过程。
<强> TIPPS 强>
我建议你继续学习这种模式的小项目,即使你认为接口不值得。继续这样做,直到你把它放进去。我个人对你的建议:
如果你认为你不知道从哪里开始以及尝试使用哪个项目,那么试试现实世界的例子就是遵循这个逻辑:
Vehicles (abstract class) -> Ferrari (extended class) -> Truck (extended class) both have wheels (property) both must be able to drive (method) they perform a 1mile match race on a street (abstract method) one is a slowpoke (extended property) one is red one is blue (extended property) and later a 3rd one comes and its a train (extended class) who's going to win (some method) Instantiate all vehicles and maintain privileges over interface and abstraction. ...something like this...
通常,包含巨大主体的类应该在单个文件中分开+包括这些+定义命名空间。否则代码墙会让你或其他人感到厌倦。使用 Eclipse ,这是维护OOP的最佳应用。
此外,如果它适合您的项目,如果您有 Linux Ubuntu ,请使用 phUML 。如果您有很多相关类,它会为您当前的构建生成一个图形图表。
phUML是基于UML的PHP中的API。它是一个开源项目,可以为几乎任何流行的编程语言生成任何可视化方案。我经常使用它,而不仅仅是PHP。只需在 Github 中克隆它,或从 dasunhegoda.com 下载,然后按照安装指南进行操作。
您也可以对此感兴趣: Typehinting on Interfaces
答案 1 :(得分:3)
抽象类允许“部分实现”(参见模板方法模式),但在这种情况下,如果所有方法都是抽象的,那么您看不到这种好处。您可以做的另一件事是包括字段,您不仅限于方法。
请记住,“抽象方法”与接口定义的契约之间存在概念上的差异。抽象方法必须由子类覆盖,该子类通过继承实现来完成。任何多态调用(向下转换)都需要每个类一个超类,否则会遇到钻石继承问题。这种基于继承的树结构是OO设计的典型。
作为对比,界面提供了履行契约的签名。只要保留签名,就可以满足许多接口的需求,因为不存在返回类层次结构以查找其他实现的问题。接口并不真正依赖于多态来实现这一点,而是基于契约。
另外需要注意的是,你可能有“受保护”的抽象方法,在界面中做这样的事情是没有意义的(实际上这样做是违法的)。
答案 2 :(得分:2)
如果abstract class
的所有方法都定义为abstract
,则必须在任何子类中定义其主体,并显示与interface
类似的行为。
好处:
使用interface
代替abstract
课程,您可以implement
使用interfaces
课程abstract
,但您只能one
abstract
一次上课。
修改强>
我发现的另一个不同之处是,constructor
班级可以有interface
而@interface Foo : UIView {}
-(id)initWithArguments:(NSString*)mess title:(NSString*)tit;
@property(nonatomic, retain) NSString *message;
@property(nonatomic, retain) NSString *title;
@end
无法有。{/ p>