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

时间:2010-02-05 23:17:54

标签: c# .net interface abstract-class

因此,假设我在C#中构建某种房地产应用程序。对于每种类型的属性,我将创建一个类,如ResidentialProperty和CommercialProperty。这两个类以及所有其他属性类将共享一些常见属性,例如Id,Title,Description和Address信息。

我希望能做的是:
a)返回仅包含基本信息的对象集合
b)能够调用一个方法,如GetProperty(id),它将创建并返回一个ResidentialProperty或CommercialProperty,或者调用GetProperties(),它将返回一个或另一个或两者的集合。

所以说,创建一个名为BasicProperty(或PropertyBase)的抽象类可能是有意义的,它包含所有常见属性,并且使ResidentialProperty和CommercialProperty从中扩展。这将解决问题#1,因为我可以创建一个返回BasicProperties集合的方法。

但是对于#2,能够返回一个属性类型或另一个属性类型,我需要一个接口(IProperty),并从它继承住宅和商业类,然后拥有GetProperty(id)和GetProperties ()返回一个IProperty对象(或者因为它们是从IProperty继承的,我可以按原样返回它们而不是接口吗?)?

现在如果我应该使用接口,我该如何处理BasicProperty类?
- 我是否将其作为摘要并实现接口?或
- 我是否将其作为摘要保留,所有3个类都实现了接口?或
- 我不是将它创建为抽象,将所有基本信息放入接口,BasicProperty,ResidentialProperty和CommercialProperty都实现了接口吗?

提前致谢, Carl J.

6 个答案:

答案 0 :(得分:3)

虽然我觉得定义一个开头的界面几乎总是总是一个好主意,只是因为它有助于你的代码在未来变得灵活,听起来好像在这种情况下你没有实际上需要来做到这一点。您的GetPropertyGetProperties方法可以使用抽象基类作为返回值。

这样想:如果我有一个名为GetShape的方法怎么办?它可能会返回Shape,对吧?假设Shape是一个抽象基类,一些派生类是TriangleSquareCircle等。

但是一个三角形一个形状,一个正方形一个形状,依此类推 - 这些中的每一个都恰好超过 >一个形状,但它们仍然是形状。因此,如果我说“给我一个形状”并且你给我一个正方形,你就像我问的那样做。那里没有搞笑的事情。

这是OOP的核心基本原则之一:派生类的实例是其基类的实例;它也只是更多

答案 1 :(得分:1)

从我可以收集的内容来看,你在谈论两件不同的事情。

  1. 班级结构
  2. 这些类的数据访问
  3. 你认为你应该创建一个抽象类来包含公共属性是正确的,这就是继承的目的:)(等等)

    但我不明白为什么你不能创建一个数据访问类,它有一个方法GetProperty(id),指定返回类型为PropertyBase

    即。

    public PropertyBase GetProperty(long id)

    GetProperty的实现中,您可以构造ResidentialPropertyCommercialProperty(基于您想要的业务/数据库逻辑)然后返回它,c#允许您这样做。

    也许我想念你了?

    HTH

    修改::

    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 { }
    }
    

答案 2 :(得分:1)

抽象类用于提供常见行为。接口用于提供一组特定的方法和属性,无论它们的行为如何。

如果您的ResidentialProperty和CommercialProperty提供了一些常见的行为,那么在抽象类中实现此行为并使每个行都继承自此类可能是有意义的。据推测,他们也会有一些自定义行为,否则不需要子类,只需要一个PropertyType属性来描述实例属于哪种类型的属性就足够了。

然后,您可以提供您认为有用的接口,IPropertyBase,IResidentialProperty和/或ICommercialProperty。这实际上取决于您是否希望将此库用作其他实现的基础,这些实现可能与您的一个或多个类具有相同的接口,但与基本抽象类的行为不同。暴露代表您的类型的接口的另一个好处是更容易模拟单元测试。

绝对不可能完全回答这个问题,因为它实际上取决于你的对象的使用方式,但我希望这个答案能为你提供一个有用的指导。

答案 3 :(得分:1)

我认为你应该避免使用抽象类,除非它绝对有意义。

通过聚合,使用组件可以为您的实体提供许多常见行为,您可以通过使用接口来宣传此行为。

我倾向于沿着这条路走下去的原因是,一旦你有了一个抽象基类,你就会被绑定使用它,因为你不能有多重继承。

迟早,你最终会遇到一种你想要多重继承的情况而且你已经搞砸了。

并不是说我是强硬派,因为我们的大量代码库确实利用了上面的基本抽象类,但那些实现接口和所有在这些类上生成的代码通过接口向他们发送,因此我们可以在以后必要时更灵活地切换基类。

答案 4 :(得分:0)

快点不要看我所看到的差异。即使实现接口,也始终可以使用抽象基类。接口无法帮助您避免代码重复(请参阅DRY principle),但它并不会强制您从任何特殊内容派生,这使得它们更容易与其他基类或接口结合使用。

另一方面,抽象基类可以删除一些重复,并且更容易更改基础中的某些内容而不触及派生类。当您实现其他人使用的类库时,后者非常好。如果您更改库中接口的内容,则该接口的所有实现都需要更改!如果您只使用一小组开发人员实现应用程序,这可能是一个非常小的问题。但正如其他人所说的那样,一个基类会迫使你从中衍生出来,如果出现这种需要,你就无法从别的东西中衍生出来。

答案 5 :(得分:0)

不要调用您的基类或接口BasicProperty或PropertyBase,只需将其称为Property。你不会同时拥有Property和BasicProperty吗?您将使用Property类或接口。

抽象类与接口几乎相同,不同之处在于抽象类可以在字段变量中存储状态。当您的属性具有类似于存储的地址的数据时,带有字段的抽象类是一种方法。

现在,类的子类化是OOD的图画书示例之一,但是还有其他区分对象的方法,请查看装饰器和行为模式。只有在需要覆盖基类的方法时才应该进行子类化。例如,请查看this