简体   繁体   English

C# - 我应该使用什么,接口,抽象类或两者?

[英]C# - What should I use, an Interface, Abstract class, or Both?

So, hypothetically, I'm building some sort of real estate application in C#. 因此,假设我在C#中构建某种房地产应用程序。 For each type of property, I'm going to create a class such as ResidentialProperty and CommercialProperty. 对于每种类型的属性,我将创建一个类,如ResidentialProperty和CommercialProperty。 These two classes as well as all other property classes will share some common properties, such as Id, Title, Description, and Address information. 这两个类以及所有其他属性类将共享一些常见属性,例如Id,Title,Description和Address信息。

What I would like to be able to do is: 我希望能做的是:
a) return a collection of objects that contain just the basic information a)返回仅包含基本信息的对象集合
b) be able to either call a method such as GetProperty(id) which will create and return either a ResidentialProperty or CommercialProperty, or call GetProperties() which will return a collection of one or the other, or both. b)能够调用一个方法,如GetProperty(id),它将创建并返回ResidentialProperty或CommercialProperty,或者调用GetProperties(),它将返回一个或另一个或两者的集合。

So with that said, it would probably make sense to create an abstract class called BasicProperty (or PropertyBase) which contains all of the common attributes, and have the ResidentialProperty and CommercialProperty extend from it. 所以说,创建一个名为BasicProperty(或PropertyBase)的抽象类可能是有意义的,它包含所有常见属性,并且从中扩展了ResidentialProperty和CommercialProperty。 This would take care of problem #1, as I could create a method that returns a collection of BasicProperties. 这将解决问题#1,因为我可以创建一个返回BasicProperties集合的方法。

But for #2, being able to return either one property type or the other, I would need an Interface (IProperty), and have the Residential and Commercial classes inherit from it, and then have the GetProperty(id) and GetProperties() return an IProperty object (or because they inherit from IProperty, can I return them as is and not as the Interface?)? 但对于#2,能够返回一个属性类型或另一个属性类型,我需要一个接口(IProperty),并从它继承Residential和Commercial类,然后让GetProperty(id)和GetProperties()返回一个IProperty对象(或者因为它们继承自IProperty,我可以按原样返回它们而不是接口吗?)?

Now if I should use an Interface, what do I do with the BasicProperty class? 现在,如果我应该使用接口,我该如何处理BasicProperty类?
- Do I leave it as an abstract and implement the Interface? - 我是否将其作为摘要并实现接口? Or 要么
- Do I leave it as an abstract and all 3 classes implement the Interface? - 我是否将其作为摘要保留,所有3个类都实现了接口? Or 要么
- Do I not create it as an abstract, put all of the basic information into the Interface, and the BasicProperty, ResidentialProperty and CommercialProperty all implement the Interface? - 我不是将它创建为抽象,将所有基本信息放入接口,BasicProperty,ResidentialProperty和CommercialProperty都实现了接口?

Thanks in advance, Carl J. 在此先感谢,Carl J.

While I feel that defining an interface to begin with is almost always a good idea, just because it helps your code to be flexible in the future, it sounds like in this case you don't actually need to do that. 虽然我觉得定义一个开头的界面几乎总是一个好主意,只是因为它有助于你的代码在未来变得灵活,听起来在这种情况下你实际上并不要这样做。 Your GetProperty and GetProperties methods can use your abstract base class as a return value. 您的GetPropertyGetProperties方法可以使用抽象基类作为返回值。

Think of it like this: What if I had a method called GetShape ? 可以这样想:如果我有一个名为GetShape的方法GetShape办? It would presumably return a Shape , right? 它可能会返回一个Shape ,对吧? Let's say Shape is an abstract base class, and some derived classes are Triangle , Square , Circle , etc. 假设Shape是一个抽象基类,一些派生类是TriangleSquareCircle等。

But a triangle is a shape, a square is a shape, and so on--each of these happens to be more than just a shape, but they are shapes nonetheless. 但是三角形一个形状,一个正方形一个形状,等等 - 每个都不仅仅是一个形状,但它们仍然是形状 So if I say "give me a shape" and you hand me a square, you're doing just as I asked. 因此,如果我说“给我一个形状”并且你给我一个正方形,你就像我问的那样做。 No funny business there. 那里没有有趣的生意。

This is one of the core underlying principles of OOP: an instance of a derived class is an instance of its base class; 这是核心底层OOP的原理中的一个:一个导出类的一个实例它的基类的一个实例; it's just also more than that. 它只是还不止于此。

From what I can gather, you are talking about two different things here. 从我可以收集的内容来看,你在谈论两件不同的事情。

  1. Class structure 班级结构
  2. Data Access of those classes 这些类的数据访问

You are correct in thinking that you should create an abstract class to contain the common properties, that's what inheritance is for :) (among other things) 你认为你应该创建一个抽象类来包含公共属性是正确的,这就是继承的含义:)(除其他外)

But I dont see why you can't create a data access class that has a method GetProperty(id) that specifies a return type of PropertyBase 但我不明白为什么你不能创建一个数据访问类,它有一个方法GetProperty(id)指定一个返回类型的PropertyBase

ie

public PropertyBase GetProperty(long id)

in the implementation of GetProperty you can construct a ResidentialProperty or CommercialProperty (based on what ever business/database logic you want) then return it, c# allows you to do that. GetProperty的实现中,您可以构建一个ResidentialPropertyCommercialProperty (基于您想要的业务/数据库逻辑)然后返回它,c#允许您这样做。

Perhaps I miss-understood you? 也许我想念你?

HTH HTH

EDIT:: 编辑::

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }

    class DataAccessLayer
    {
        public PropertyBase GetSomething(int id)
        {
            if (id > 10)
                return new CommercialProperty();
            else
                return new ResidentialProperty();
        }

    }

    class PropertyBase { }
    class ResidentialProperty : PropertyBase { } 
    class CommercialProperty : PropertyBase { }
}

An abstract class is used to provide common behaviour. 抽象类用于提供常见行为。 An interface is used to provide a specific set of methods and properties, regardless of how they behave. 接口用于提供一组特定的方法和属性,无论它们的行为如何。

If your ResidentialProperty and CommercialProperty provide some common behaviour then it probably makes sense to implement this behaviour in an abstract class and have each of them inherit from this class. 如果您的ResidentialProperty和CommercialProperty提供了一些常见的行为,那么在抽象类中实现此行为并让它们中的每一个都继承自此类可能是有意义的。 Presumably they also will have some custom behaviour ,otherwise there is no need to sub-class, it would then be sufficient just to have a PropertyType property to describe which type of Property the instance is. 据推测,他们也会有一些自定义行为,否则不需要子类,只需要一个PropertyType属性来描述实例属于哪种类型的Property就足够了。

You can then provide as many interfaces as you feel would be useful, IPropertyBase, IResidentialProperty and/or ICommercialProperty. 然后,您可以提供您认为有用的接口,IPropertyBase,IResidentialProperty和/或ICommercialProperty。 It really depends on whether you expect this library to be used a base for other implementations which may have the same interface as one or more of your classes, but not the same behaviour as your base abstract class. 这实际上取决于您是否希望将此库用作其他实现的基础,这些实现可能与您的一个或多个类具有相同的接口,但与基本抽象类的行为不同。 The other benefit of exposing interfaces which represent your types is easier mocking for unit testing. 暴露代表您的类型的接口的另一个好处是更容易模拟单元测试。

It's not really possible to answer this question absolutely because it really depends on how your objects are likely to be used, but I hope this answer provides you with a useful guideline. 绝对不可能完全回答这个问题,因为它实际上取决于你的对象的使用方式,但我希望这个答案能为你提供一个有用的指导方针。

It is my opinion that you should avoid using abstract classes unless it absolutely makes sense you should. 我认为你应该避免使用抽象类,除非你应该完全有意义。

A lot of the common behaviour can be given to your entities through aggregation, using components and you can publicise this behaviour through the use of interfaces. 通过聚合,使用组件可以为您的实体提供许多常见行为,您可以通过使用接口来公开此行为。

The reason I tend to go down this route, is that once you have an abstract base class, you're tied to using it, as you can't have multiple inheritance. 我倾向于沿着这条路走下去的原因是,一旦你有了一个抽象的基类,你就会被绑定使用它,因为你不能拥有多重继承。

Sooner or later, you end up with a situation in which you DO want multiple inheritance and you're screwed. 迟早,你最终会遇到一种你需要多重继承的情况,而你却被搞砸了。

Not that I'm a hardliner on this, because plenty of our code-base does utilise base abstract classes for the above, but those implement the interfaces and all the code enacting on those classes talk to them through the interfaces, so we can switch out the base classes for something more flexible later if necessary. 并不是说我是强硬派,因为我们的大量代码库确实利用了上面的基本抽象类,但那些实现了接口,所有在这些类上生成的代码通过接口与它们通信,所以我们可以切换如有必要,稍后可以更灵活地输出基类。

A quick not about the difference as I see it. 我看到的很快就没有差别了。 You can always use an abstract base class even when you implement interfaces. 即使实现接口,也始终可以使用抽象基类。 Interfaces does not help you avoid code duplication which you should (see the DRY principle ) but it doesn't force you to derive from anything special which makes them easier to combine with other base classes or interfaces. 接口不能帮助您避免代码重复(请参阅DRY原则 ),但它不会强制您从任何特殊的东西派生,这使得它们更容易与其他基类或接口组合。

An abstract base class on the other hand can remove some duplication and it is easier to change some things in the base without touching the derived classes. 另一方面,抽象基类可以删除一些重复,并且更容易更改基础中的某些内容而不触及派生类。 The latter is very nice when you implement a class library that others use. 当您实现其他人使用的类库时,后者非常好。 If you change things in interfaces in a library, all implementations of that interface needs to change! 如果您更改库中接口的内容,则该接口的所有实现都需要更改! This might be a very small problem if you only implement an application with a small group of developers. 如果您只使用一小组开发人员实现应用程序,这可能是一个非常小的问题。 But as other has said, a base class forces you to derive from it and then you cannot derive from something else if that need should appear. 但正如其他人所说的那样,基类迫使你从中衍生出来,然后如果出现这种需要你就无法从别的东西中衍生出来。

Don't call your base class or interface BasicProperty or PropertyBase, just call it Property. 不要调用您的基类或接口BasicProperty或PropertyBase,只需将其称为Property。 You will not have both a Property and a BasicProperty, will you? 你不会同时拥有Property和BasicProperty吗? You will act with Property classes or interfaces. 您将使用Property类或接口。

An abstract class is almost the same as an interface with the difference that the abstract class can store state in field variables. 抽象类与接口几乎相同,不同之处在于抽象类可以在字段变量中存储状态。 When your Properties have data like the address that is stored an abstract class with a field is one way to do that. 当您的属性具有类似于存储的地址的数据时,带有字段的抽象类是一种方法。

Now the subclassing of a class is one of the picture book examples of OOD, but there are other ways of differentiating objects than that, look at the decorator and behavior patterns. 现在,类的子类化是OOD的图画书示例之一,但是还有其他区分对象的方法,请查看装饰器和行为模式。 You should subclass only if you need to override methods of the base class. 只有在需要覆盖基类的方法时才应该进行子类化。 Have a look at this for example. 例如,看看这个

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM