何时使用接口而不是抽象类,反之亦然?

发布于 2024-07-12 07:39:50 字数 110 浏览 10 评论 0原文

这可能是一个通用的 OOP 问题。 我想根据接口和抽象类的用法对它们进行一般比较。

什么时候需要使用接口,什么时候需要使用抽象类

This may be a generic OOP question. I wanted to do a generic comparison between an interface and an abstract class on the basis of their usage.

When would one want to use an interface and when would one want to use an abstract class?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(25

旧街凉风 2024-07-19 07:39:50

我写了一篇关于此的文章:

抽象类和接口< /a>

总结:

当我们谈论抽象类时,我们正在定义对象类型的特征; 指定对象是什么

当我们谈论接口并定义我们承诺提供的功能时,我们谈论的是建立一个关于对象可以做什么的契约。

I wrote an article about that:

Abstract classes and interfaces

Summarizing:

When we talk about abstract classes we are defining characteristics of an object type; specifying what an object is.

When we talk about an interface and define capabilities that we promise to provide, we are talking about establishing a contract about what the object can do.

痞味浪人 2024-07-19 07:39:50

抽象类可以具有共享状态或功能。 接口只是提供状态或功能的承诺。 一个好的抽象类将减少必须重写的代码量,因为它的功能或状态可以共享。 接口没有定义可共享的信息

An abstract class can have shared state or functionality. An interface is only a promise to provide the state or functionality. A good abstract class will reduce the amount of code that has to be rewritten because it's functionality or state can be shared. The interface has no defined information to be shared

娇俏 2024-07-19 07:39:50

就我个人而言,我几乎从来不需要编写抽象类。

大多数时候我看到抽象类被(错误)使用,这是因为抽象类的作者正在使用“模板方法”模式。

“模板方法”的问题在于它几乎总是有点可重入的 - “派生”类不仅知道它正在实现的基类的“抽象”方法,而且还知道基类的公共方法,尽管大多数时候它不需要调用它们。

(过于简化)示例:

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

所以在这里,此类的作者编写了一个通用算法,并打算让人们通过提供自己的“钩子”(在本例中为“比较”方法)来“专门化”它来使用它。

所以预期的用法是这样的:

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

这样做的问题是你过度地将两个概念结合在一起:

  1. 一种比较两个项目的方法(哪个项目应该放在第一位)
  2. 一种对项目进行排序的方法(即快速排序与合并排序等)。 )

在上面的代码中,理论上,“compare”方法的作者可以重新进入回调到超类“Sort”方法......即使在实践中他们永远不会想要或不需要做这个。

您为这种不必要的耦合付出的代价是很难更改超类,并且在大多数 OO 语言中,不可能在运行时更改它。

另一种方法是使用“策略”设计模式:

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

所以现在请注意:我们拥有的只是接口以及这些接口的具体实现。 实际上,您实际上不需要任何其他东西来进行高级面向对象设计。

为了“隐藏”我们已经通过使用“QuickSort”类和“NameComparator”实现“名称排序”的事实,我们仍然可以在某处编写工厂方法:

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

任何时候抽象类,你可以这样做......即使基类和派生类之间存在自然的可重入关系,通常也需要使它们显式化。

最后一个想法:我们上面所做的就是通过使用“QuickSort”函数和“NameComparison”函数“组合”一个“NameSorting”函数......在函数式编程语言中,这种编程风格变得更加自然,用更少的代码。

Personally, I almost never have the need to write abstract classes.

Most times I see abstract classes being (mis)used, it's because the author of the abstract class is using the "Template method" pattern.

The problem with "Template method" is that it's nearly always somewhat re-entrant - the "derived" class knows about not just the "abstract" method of its base class that it is implementing, but also about the public methods of the base class, even though most times it does not need to call them.

(Overly simplified) example:

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

So here, the author of this class has written a generic algorithm and intends for people to use it by "specializing" it by providing their own "hooks" - in this case, a "compare" method.

So the intended usage is something like this:

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

The problem with this is that you've unduly coupled together two concepts:

  1. A way of comparing two items (what item should go first)
  2. A method of sorting items (i.e. quicksort vs merge sort etc.)

In the above code, theoretically, the author of the "compare" method can re-entrantly call back into the superclass "Sort" method... even though in practise they will never want or need to do this.

The price you pay for this unneeded coupling is that it's hard to change the superclass, and in most OO languages, impossible to change it at runtime.

The alternative method is to use the "Strategy" design pattern instead:

interface IComparator
{
    bool compare(object lhs, object rhs);
}

class QuickSorter
{
    private readonly IComparator comparator;
    public QuickSorter(IComparator comparator)
    {
        this.comparator = comparator;
    }

    public void Sort(object[] items)
    {
        // usual code but call comparator.Compare();
    }
}

class NameComparator : IComparator
{
    bool compare(object lhs, object rhs)
    {
        // same code as before;
    }
}

So notice now: All we have are interfaces, and concrete implementations of those interfaces. In practise, you don't really need anything else to do a high level OO design.

To "hide" the fact that we've implemented "sorting of names" by using a "QuickSort" class and a "NameComparator", we might still write a factory method somewhere:

ISorter CreateNameSorter()
{
    return new QuickSorter(new NameComparator());
}

Any time you have an abstract class you can do this... even when there is a natural re-entrant relationship between the base and derived class, it usually pays to make them explicit.

One final thought: All we've done above is "compose" a "NameSorting" function by using a "QuickSort" function and a "NameComparison" function... in a functional programming language, this style of programming becomes even more natural, with less code.

独闯女儿国 2024-07-19 07:39:50

我的两点意见:

接口基本上定义了一个契约,任何实现类都必须遵守该契约(实现接口成员)。 它不包含任何代码。

另一方面,抽象类可以包含代码,并且可能有一些标记为抽象的方法,继承类必须实现这些方法。

我使用抽象类的罕见情况是,当我有一些默认功能时,继承类可能对重写某些默认功能不感兴趣,例如抽象基类,某些专用类继承自该抽象基类。

示例(一个非常基本的示例!):考虑一个名为 Customer 的基类,它具有诸如 CalculatePayment()CalculateRewardPoints() 等抽象方法以及一些诸如 >GetName()SavePaymentDetails()

RegularCustomerGoldCustomer 等专门类将从 Customer 基类继承,并实现自己的 CalculatePayment() 和 < code>CalculateRewardPoints() 方法逻辑,但重复使用 GetName()SavePaymentDetails() 方法。

您可以向抽象类(即非抽象方法)添加更多功能,而不会影响使用旧版本的子类。 而向接口添加方法会影响实现它的所有类,因为它们现在需要实现新添加的接口成员。

具有所有抽象成员的抽象类类似于接口。

My two cents:

An interface basically defines a contract, that any implementing class must adhere to(implement the interface members). It does not contain any code.

On the other hand, an abstract class can contain code, and there might be some methods marked as abstract which an inheriting class must implement.

The rare situations I've used abstract classes is when i have some default functionality that the inheriting class might not be interesting in overriding, in say an abstract base class, that some specialized classes inherit from.

Example(a very rudimentary one!):Consider a base class called Customer which has abstract methods like CalculatePayment(), CalculateRewardPoints() and some non-abstract methods like GetName(), SavePaymentDetails().

Specialized classes like RegularCustomer and GoldCustomer will inherit from the Customer base class and implement their own CalculatePayment() and CalculateRewardPoints() method logic, but re-use the GetName() and SavePaymentDetails() methods.

You can add more functionality to an abstract class(non abstract methods that is) without affecting child classes which were using an older version. Whereas adding methods to an interface would affect all classes implementing it as they would now need to implement the newly added interface members.

An abstract class with all abstract members would be similar to an interface.

沉睡月亮 2024-07-19 07:39:50

好吧,我自己刚刚“理解”了这一点 - 这是用外行的话来说的(如果我错了,请随时纠正我) - 我知道这个话题太老了,但有一天其他人可能会偶然发现它......

抽象类允许您可以创建一个蓝图,并允许您另外构建(实现)您希望其所有后代拥有的属性和方法。

另一方面,接口只允许您声明您希望具有给定名称的属性和/或方法存在于实现它的所有类中 - 但不指定您应该如何实现它。 此外,一个类可以实现多个接口,但只能扩展一个抽象类。 接口更像是一种高级架构工具(如果您开始掌握设计模式,它会变得更加清晰) - 抽象在两个阵营中都有立足之地,也可以执行一些肮脏的工作。

为什么要使用其中一种而不是另一种? 前者允许对后代进行更具体的定义,后者允许更大的多态性。 最后一点对于最终用户/编码人员很重要,他们可以利用此信息以各种组合/形状实现 API(接口),以满足他们的需求。

我认为这对我来说是“灵光乍现”的时刻 - 少从作者的角度来思考接口,而更多地从链中后期为项目添加实现或扩展项目的任何编码人员的角度来思考接口。 API。

OK, having just "grokked" this myself - here it is in layman's terms (feel free to correct me if I am wrong) - I know this topic is oooooold, but someone else might stumble across it one day...

Abstract classes allow you to create a blueprint, and allow you to additionally CONSTRUCT (implement) properties and methods you want ALL its descendants to possess.

An interface on the other hand only allows you to declare that you want properties and/or methods with a given name to exist in all classes that implement it - but doesn't specify how you should implement it. Also, a class can implement MANY interfaces, but can only extend ONE Abstract class. An Interface is more of a high level architectural tool (which becomes clearer if you start to grasp design patterns) - an Abstract has a foot in both camps and can perform some of the dirty work too.

Why use one over the other? The former allows for a more concrete definition of descendants - the latter allows for greater polymorphism. This last point is important to the end user/coder, who can utilise this information to implement the A.P.I(nterface) in a variety of combinations/shapes to suit their needs.

I think this was the "lightbulb" moment for me - think about interfaces less from the author's perpective and more from that of any coder coming later in the chain who is adding implementation to a project, or extending an API.

生死何惧 2024-07-19 07:39:50

如果你脑子里有清晰的概念,什么时候做什么是一件非常简单的事情。

抽象类可以派生,而接口可以实现。 两者之间存在一些差异。 当派生抽象类时,派生类和基类之间的关系是“是”关系。 例如,狗是动物,羊是动物,这意味着派生类从基类继承了一些属性。

而对于接口的实现,关系是“可以”。 例如,狗可以是间谍狗。 狗可以是马戏团的狗。 狗可以是赛狗。 这意味着您实施某些方法来获取某些东西。

我希望我说清楚了。

When to do what is a very simple thing if you have the concept clear in your mind.

Abstract classes can be Derived whereas Interfaces can be Implemented. There is some difference between the two. When you derive an Abstract class, the relationship between the derived class and the base class is 'is a' relationship. e.g., a Dog is an Animal, a Sheep is an Animal which means that a Derived class is inheriting some properties from the base class.

Whereas for implementation of interfaces, the relationship is "can be". e.g., a Dog can be a spy dog. A dog can be a circus dog. A dog can be a race dog. Which means that you implement certain methods to acquire something.

I hope I am clear.

携余温的黄昏 2024-07-19 07:39:50

什么时候更喜欢抽象类而不是接口?

  1. 如果计划在程序/项目的整个生命周期中更新基类,那么最好允许基类成为抽象类(
  2. 如果有人尝试)要为层次结构中密切相关的对象构建主干,使用抽象类非常有益

何时更喜欢接口而不是抽象类?

  1. 如果不处理大量层次结构类型框架,接口将是一个不错的选择,
  2. 因为抽象类不支持多重继承(钻石问题),接口可以拯救世界

When to prefer an abstract class over interface?

  1. If one plans on updating a base class throughout the life of a program/project, it is best to allow that the base class be an abstract class
  2. If one is trying to build a backbone for objects that are closely related in a hierarchy, it is highly beneficial to use an abstract class

When to prefer an interface over abstract class?

  1. If one is not dealing with a massive hierarchical type of framework, interfaces would be a great choice
  2. Because multiple inheritance is not supported with abstract classes(diamond problem), interfaces can save the day
痴意少年 2024-07-19 07:39:50

1.如果您要创建为不相关的类提供通用功能的东西,请使用接口。

2.如果您要为层次结构中密切相关的对象创建某些内容,请使用抽象类。

1.If you are creating something that provides common functionality to unrelated classes, use an interface.

2.If you are creating something for objects that are closely related in a hierarchy, use an abstract class.

白况 2024-07-19 07:39:50

类可能仅继承自一个基类,因此如果要使用抽象类为一组类提供多态性,它们必须全部继承自该类。 抽象类还可以提供已经实现的成员。 因此,您可以使用抽象类确保一定数量的相同功能,但不能使用接口。

以下是一些建议,可帮助您决定是使用接口还是抽象类来为组件提供多态性。

  • 如果您预计创建组件的多个版本,请创建一个抽象类。 抽象类提供了一种简单易用的方法来对组件进行版本控制。 通过更新基类,所有继承类都会随着更改自动更新。 另一方面,接口一旦以这种方式创建就无法更改。 如果需要新版本的接口,您必须创建一个全新的接口。
  • 如果您创建的功能对各种不同的对象都很有用,请使用接口。 抽象类应主要用于密切相关的对象,而接口最适合为不相关的类提供通用功能。
  • 如果您正在设计小而简洁的功能,请使用接口。 如果您正在设计大型功能单元,请使用抽象类。
  • 如果您想在组件的所有实现中提供通用的、已实现的功能,请使用抽象类。 抽象类允许您部分实现您的类,而接口不包含任何成员的实现。

复制自:

http://msdn.microsoft.com/en -us/library/scsyfw1d%28v=vs.71%29.aspx

Classes may inherit from only one base class, so if you want to use abstract classes to provide polymorphism to a group of classes, they must all inherit from that class. Abstract classes may also provide members that have already been implemented. Therefore, you can ensure a certain amount of identical functionality with an abstract class, but cannot with an interface.

Here are some recommendations to help you to decide whether to use an interface or an abstract class to provide polymorphism for your components.

  • If you anticipate creating multiple versions of your component, create an abstract class. Abstract classes provide a simple and easy way to version your components. By updating the base class, all inheriting classes are automatically updated with the change. Interfaces, on the other hand, cannot be changed once created in that way. If a new version of an interface is required, you must create a whole new interface.
  • If the functionality you are creating will be useful across a wide range of disparate objects, use an interface. Abstract classes should be used primarily for objects that are closely related, whereas interfaces are best suited for providing common functionality to unrelated classes.
  • If you are designing small, concise bits of functionality, use interfaces. If you are designing large functional units, use an abstract class.
  • If you want to provide common, implemented functionality among all implementations of your component, use an abstract class. Abstract classes allow you to partially implement your class, whereas interfaces contain no implementation for any members.

Copied from:

http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx

拥抱我好吗 2024-07-19 07:39:50

我写了一篇关于何时使用抽象类以及何时使用接口的文章。 除了“一个 IS-A...和一个 CAN-DO...”之外,它们之间还有很多区别。 对我来说,这些都是预设的答案。 我提到了何时使用它们中的一些原因。 希望能帮助到你。

http://codeofdoom.com/wordpress/2009/02/12/learn-this-when-to-use-an-abstract-class-and-an-interface/

I wrote an article of when to use an abstract class and when to use an interface. There is a lot more of a difference between them other than "one IS-A... and one CAN-DO...". To me, those are canned answers. I mention a few reasons when to use either of them. Hope it helps.

http://codeofdoom.com/wordpress/2009/02/12/learn-this-when-to-use-an-abstract-class-and-an-interface/

幽梦紫曦~ 2024-07-19 07:39:50

我认为最简洁的表达方式如下:

共享属性=> 抽象类。
共享功能 => 界面。

更简单地说...

抽象类示例:

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

由于动物具有共享属性(在本例中为腿的数量),因此创建一个包含此共享属性的抽象类是有意义的。 这也允许我们编写对该属性进行操作的通用代码。 例如:

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

界面示例:

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

请注意,Vuvuzelas 和汽车是完全不同的东西,但它们具有共享的功能:发出声音。 因此,接口在这里是有意义的。 此外,它还允许程序员将发出声音的事物分组到一个公共接口下 - 在本例中为 IMakeSound。 通过这种设计,您可以编写以下代码:

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

您能说出它会输出什么吗?

最后,您可以将两者结合起来。

组合示例:

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

在这里,我们要求所有BaseAnimal发出声音,但我们还不知道它的实现。 在这种情况下,我们可以抽象接口实现并将其实现委托给其子类。

最后一点,还记得在抽象类示例中我们如何能够操作不同对象的共享属性,以及在接口示例中我们如何能够调用不同对象的共享功能吗? 在最后一个例子中,我们可以两者都做。

I think the most succinct way of putting it is the following:

Shared properties => abstract class.
Shared functionality => interface.

And to put it less succinctly...

Abstract Class Example:

public abstract class BaseAnimal
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }
}

public class Dog : BaseAnimal
{
    public Dog() : base(4) { }
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }
}

Since animals have a shared property - number of legs in this case - it makes sense to make an abstract class containing this shared property. This also allows us to write common code that operates on that property. For example:

public static int CountAllLegs(List<BaseAnimal> animals)
{
    int legCount = 0;
    foreach (BaseAnimal animal in animals)
    {
        legCount += animal.NumberOfLegs;
    }
    return legCount;
}

Interface Example:

public interface IMakeSound
{
    void MakeSound();
}

public class Car : IMakeSound
{
    public void MakeSound() => Console.WriteLine("Vroom!");
}

public class Vuvuzela : IMakeSound
{
    public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");        
}

Note here that Vuvuzelas and Cars are completely different things, but they have shared functionality: making a sound. Thus, an interface makes sense here. Further, it will allow programmers to group things that make sounds together under a common interface -- IMakeSound in this case. With this design, you could write the following code:

List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());

foreach (IMakeSound soundMaker in soundMakers)
{
    soundMaker.MakeSound();
}

Can you tell what that would output?

Lastly, you can combine the two.

Combined Example:

public interface IMakeSound
{
    void MakeSound();
}

public abstract class BaseAnimal : IMakeSound
{
    public int NumberOfLegs { get; set; }

    protected BaseAnimal(int numberOfLegs)
    {
        NumberOfLegs = numberOfLegs;
    }

    public abstract void MakeSound();
}

public class Cat : BaseAnimal
{
    public Cat() : base(4) { }

    public override void MakeSound() => Console.WriteLine("Meow!");
}

public class Human : BaseAnimal 
{
    public Human() : base(2) { }

    public override void MakeSound() => Console.WriteLine("Hello, world!");
}

Here, we're requiring all BaseAnimals make a sound, but we don't know its implementation yet. In such a case, we can abstract the interface implementation and delegate its implementation to its subclasses.

One last point, remember how in the abstract class example we were able to operate on the shared properties of different objects and in the interface example we were able to invoke the shared functionality of different objects? In this last example, we could do both.

自由范儿 2024-07-19 07:39:50

如果以下任何陈述适用于您的情况,请考虑使用抽象类

  1. 您希望在几个密切相关的类之间共享代码。
  2. 您期望扩展抽象类的类具有许多通用方法或字段,或者需要除 public 之外的访问修饰符(例如 protected 和 private)。
  3. 您想要声明非静态或非最终字段。 这使您能够定义可以访问和修改它们所属对象的状态的方法。

如果以下任何陈述适用于您的情况,请考虑使用接口

  1. 您希望不相关的类将实现您的接口。 例如,Comparable 和 Cloneable 接口是由许多不相关的类实现的。
  2. 您想要指定特定数据类型的行为,但不关心谁实现其行为。
  3. 您想要利用多重继承。

来源

Consider using abstract classes if any of these statements apply to your situation:

  1. You want to share code among several closely related classes.
  2. You expect that classes that extend your abstract class have many common methods or fields or require access modifiers other than public (such as protected and private).
  3. You want to declare non-static or non-final fields. This enables you to define methods that can access and modify the state of the object to which they belong.

Consider using interfaces if any of these statements apply to your situation:

  1. You expect that unrelated classes would implement your interface. For example, the interfaces Comparable and Cloneable are implemented by many unrelated classes.
  2. You want to specify the behavior of a particular data type, but not concerned about who implements its behavior.
  3. You want to take advantage of multiple inheritances.

Source

蓦然回首 2024-07-19 07:39:50

不同语言的答案有所不同。 例如,在 Java 中,一个类可以实现(继承)多个接口,但只能继承一个抽象类。 因此接口为您提供了更大的灵活性。 但在 C++ 中却并非如此。

The answers vary between languages. For example, in Java a class can implement (inherit from) multiple interfaces but only inherit from one abstract class. So interfaces give you more flexibility. But this is not true in C++.

风蛊 2024-07-19 07:39:50

如果您想提供一些基本实现,请使用抽象类。

Use an abstract class if you want to provide some basic implementations.

仄言 2024-07-19 07:39:50

对我来说,在很多情况下我会使用接口。 但在某些情况下我更喜欢抽象类。

OO中的类一般指的是实现。 当我想将一些实现细节强加给子类时,我使用抽象类,否则我会使用接口。

当然,抽象类不仅在强制实现方面有用,而且在许多相关类之间共享一些特定细节方面也很有用。

For me, I would go with interfaces in many cases. But I prefer abstract classes in some cases.

Classes in OO generaly refers to implementation. I use abstract classes when I want to force some implementation details to the childs else I go with interfaces.

Of course, abstract classes are useful not only in forcing implementation but also in sharing some specific details among many related classes.

挥剑断情 2024-07-19 07:39:50

在java中,您可以从一个(抽象)类继承来“提供”功能,并且可以实现许多接口来“确保”功能

in java you can inherit from one (abstract) class to "provide" functionality and you can implement many interfaces to "ensure" functionality

眼眸印温柔 2024-07-19 07:39:50

这可能是一个非常困难的调用...

我可以给出一个指针:一个对象可以实现许多接口,而一个对象只能继承一个基类(在像 c# 这样的现代 OO 语言中,我知道 C++ 具有多重继承 -但这不是让人皱眉吗?)

This can be a very difficult call to make...

One pointer I can give: An object can implement many interfaces, whilst an object can only inherit one base class( in a modern OO language like c#, I know C++ has multiple inheritance - but isn't that frowned upon?)

极致的悲 2024-07-19 07:39:50

纯粹基于继承,您可以使用抽象来定义明确的后代、抽象关系(即动物->猫)和/或需要继承虚拟或非公共属性,特别是共享状态(接口无法支持)。

您应该尽可能地尝试组合(通过依赖注入)而不是继承,并注意作为契约的接口支持单元测试、关注点分离和(语言不同)多重继承,而抽象则不能。

Purely on the basis of inheritance, you would use an Abstract where you're defining clearly descendant, abstract relationships (i.e. animal->cat) and/or require inheritance of virtual or non-public properties, especially shared state (which Interfaces cannot support).

You should try and favour composition (via dependency injection) over inheritance where you can though, and note that Interfaces being contracts support unit-testing, separation of concerns and (language varying) multiple inheritance in a way Abstracts cannot.

硪扪都還晓 2024-07-19 07:39:50

接口比抽象类更好的一个有趣的地方是当您需要向一组(相关或不相关)对象添加额外的功能时。 如果您无法为它们提供一个基本抽象类(例如,它们被密封或已经有父级),您可以为它们提供一个虚拟(空)接口,然后只需为该接口编写扩展方法。

One interesting location where interfaces fare better than abstract classes is when you need to add extra functionality to a group of (related or unrelated) objects. If you cannot give them a base abstract class (e.g., they are sealed or already have a parent), you can give them a dummy (empty) interface instead, and then simply write extension methods for that interface.

浪漫人生路 2024-07-19 07:39:50

基本经验规则是:对于“名词”使用 Abstract 类,对于“动词”使用接口

例如:car 是一个抽象类,drive,我们可以把它做成一个接口。

Basic thumb rule is: For "Nouns" use Abstract class and for "Verbs" use interface

E.g: car is an abstract class and drive, we can make it an interface.

我一直都在从未离去 2024-07-19 07:39:50

简短的回答:抽象类允许您创建子类可以实现或重写的功能。 界面仅允许您定义功能,而不能实现它。 尽管一个类只能扩展一个抽象类,但它可以利用多个接口。

The short answer: An abstract class allows you to create functionality that subclasses can implement or override. An interface only allows you to define functionality, not implement it. And whereas a class can extend only one abstract class, it can take advantage of multiple interfaces.

南烟 2024-07-19 07:39:50

抽象类可以有实现。

接口没有实现,它只是定义一种契约。

还可能存在一些与语言相关的差异:例如,C# 没有多重继承,但可以在一个类中实现多个接口。

An abstract class can have implementations.

An interface doesn't have implementations, it simply defines a kind of contract.

There can also be some language-dependent differences: for example C# does not have multiple inheritance, but multiple interfaces can be implemented in a class.

风筝在阴天搁浅。 2024-07-19 07:39:50

如果我们有一个对于所有派生类都相同的实现,那么最好使用抽象类而不是接口。 当我们有一个接口时,我们可以将实现移动到任何实现接口的类。 在抽象类中,它避免了代码重复并共享所有派生类的实现。 这些接口允许开发松散耦合的系统,这有助于更好的测试。

If we have an implementation that will be the same for all the derived classes and at that time it is better to use the abstract class over an interface. when we have an interface, we can move our implementation to any class that implements interface. In abstract class, it avoids code duplication and share the implementation for all derived class. The interfaces allow to develop loosely coupled systems which helps for better testing.

蓝海 2024-07-19 07:39:50

两者都是类定义的契约

结论1:两个意图都是对象泛化

在定义抽象类时,它们也可以有默认的实现

结论2:区分在于行为泛化设计

在利用抽象类时,类只能继承一个抽象类

结论3:抽象类在使用上有局限性。 它的意思是
行为泛化的局限性

最终结论-何时使用:区分是在行为泛化级别

在设计类的行为时,如果功能在概念上只是限制在确定的类中或者换句话说,是在确定的类之间共享,使用抽象类。 但是,如果功能比确定的类更通用,或者我们可以/想要向其他类添加功能,请使用接口作为契约。

Both are contract for class definition:

Conclusion 1: Both intent is object generalization

In defining abstract classes, they can have default implementation also.

Conclusion 2: distinguish is in Behavioral generalization Design

In utilizing abstract classes, classes can inherit from just one abstract class

Conclusion 3: abstract class has limitation in utilizing. It means
limitation in Behavioral generalization.

Final Conclusion-When to use which: Distinguish is in behavioral generalization level

In designing behavioral of classes, If functionality is just conceptually limited among determined classes or in other word, is share among determined class, use abstract class. but if functionality is more general than determined classes or we can/want add functionality to other classes, use interface as a contract.

甜心小果奶 2024-07-19 07:39:50

Vehicle包含car、tank、plane、cart等。

抽象类Vehicle又可以有car、tank、plane、cart等子类。

public abstract Vehicle {...}

public Car extends Vehicle {...}

public Tank extends Vehicle {...}

那么,什么是Movable呢? 几乎所有的东西!
然后

石头、蛋糕、汽车、星球、星系,甚至你都是可移动的!

其中大部分也是 Observable!

那么,什么是 Eatable? 一切都根据一款名为“美味星球”的游戏......
然后是

石头、汽车、星球、星系,甚至是时间!

public interface Movable {...}
public interface Observable {...}
public interface Eatable {...}

public class Stone implements Movable, Eatable, Observable {...}

public class Time implements Eatable, Observable {...}

public class Stupidity implements Observable {...}

最后!

public class ChocolateCar extends Vehicle implements Eatable {...}

Vehicle contains car, tank, plane, cart, etc.

Abstract class Vehicle could have subclasses such as car, tank, plane, cart, etc.

public abstract Vehicle {...}

public Car extends Vehicle {...}

public Tank extends Vehicle {...}

So, what is Movable? almost everything!
Then

stone, cake, car, planet, galaxy, even you are Movable!

most of them are also Observable!

And, what is Eatable? Everything according to a game called Tasty Planet...
Then

stone, car, planet, galaxy, even time!

public interface Movable {...}
public interface Observable {...}
public interface Eatable {...}

public class Stone implements Movable, Eatable, Observable {...}

public class Time implements Eatable, Observable {...}

public class Stupidity implements Observable {...}

Finally!

public class ChocolateCar extends Vehicle implements Eatable {...}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文