Interface or abstract class?
对于我的新宠物项目,我有一个设计问题,这已经决定了,但我也想要一些其他的意见。
我有两个课程(简化):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class MyObject { string name {get;set;} enum relation {get;set;} int value {get;set;} } class MyObjectGroup { string name {get;set;} enum relation {get;set;} int value {get;set;} List<MyObject> myobjects {get;set;} } |
在项目后期,
- 创建接口:
IObject 。 - 创建一个抽象类:
ObjectBase 。
我决定采用接口的方式,稍后在代码中我不能每次都写
第二,在整个故事中加入
一般来说,我在这种情况下使用的方法是既有接口又有抽象类。接口定义了接口。抽象类只是一个助手。
这种方法你真的不会出错。接口为您提供了更改实现的灵活性。抽象类为您提供了不必强制使用的样板和帮助程序代码,否则,如果您的方法是用抽象类显式定义的,那么您将使用样板和帮助程序代码。
这些是接口和抽象类之间的一些区别。
一个类可以继承(实现)一个或多个接口。因此在C中,接口被用来实现多重继承。< BR>一个类只能继承一个抽象类。
接口不能提供任何代码,只能提供签名。< BR>抽象类可以提供完整的默认代码和/或只提供必须重写的细节。
3a.接口不能有子、函数、属性等的访问修饰符。一切都假定为公共的。< BR>抽象类可以包含子类、函数和属性的访问修饰符。
接口用于定义类的外围能力。例如,
如果各种实现只共享方法签名,那么最好使用接口。< BR>如果不同的实现类型相同,并且使用公共行为或状态,那么抽象类更适合使用。
6a.如果我们向接口添加一个新方法,那么我们必须跟踪接口的所有实现,并定义新方法的实现。< BR>如果我们向抽象类添加一个新方法,那么我们可以选择提供默认实现,因此所有现有的代码都可以正常工作。
7a.接口不能定义字段。< BR>抽象类可以定义字段和常量。
8a.接口不能有构造函数。< BR>抽象类可以实现默认的构造函数。
9a.接口只能从其他接口继承。< BR>9B.抽象类可以从接口、抽象类甚至类继承。
在有理由使用基类之前,该接口将是我的默认接口,因为它为我们做的决策更少。
我不会让
您的序列化要求是什么?可能有更好的选择…但是,对于许多序列化程序来说,基类比接口更容易。例如,对于
1 2 3 |
(具体方法取决于序列化程序)
通常,您应该将接口视为某些类型实现的契约,而将抽象类视为继承层次结构中本身不存在的节点(即,派生类和基本抽象类之间存在"is a"关系)。然而,在实践中,您可能需要在其他情况下使用接口,比如当您需要多个继承时。
例如,
接口将允许您定义一个"契约",对象将需要通过交付接口所描述的属性和方法来实现该契约。您可以通过接口类型的变量来引用对象,这可能会导致对提供的确切内容产生一些混淆。
基类提供了构建继承"树"的机会,其中更复杂的类(公共的"类型")构建在更简单的"基类"的基础上。OO中经典而烦人的例子通常是一个"形状"的基类,由三角形、正方形等继承。
主要的一点是,对于一个接口,您需要为实现它的每个类提供整个契约,对于继承树(基类),您只需要更改/添加子类特有的属性和方法,公共属性和方法仍保留在基类中。
在上面的示例中,我将让"myObjectGroup"对象继承基本的"myObject"类,在这里我可以看到,从接口中什么也得不到。
在设计类时,架构师有两个想法。
如果一个实体有多个实现,那么将对象的行为与其实现分离是可维护性和去耦的关键之一。分离可以通过抽象类或接口实现,但哪一个是最好的?让我们举个例子来检查一下。
让我们以一个开发场景为例,在这个场景中,事物(请求、类模型等)变化非常频繁,您必须交付应用程序的某些版本。
最初的问题陈述:您必须为印度铁路创建一个"火车"类,该类铁路在1970年的行为为Maxspeed。
1。抽象类业务建模V 0.0(初始问题)最初的问题陈述:您必须为印度铁路创建一个
1 2 3 | public abstract class Train { public int maxSpeed(); } |
V 1.0(更改问题1)改变了问题陈述:你必须为印度铁路创建一个
1 2 3 | public abstract class DieselTrain extends train { public int maxFuelCapacity (); } |
V 2.0(更改问题2)Chanded问题陈述:你必须为印度铁路创建一个
1 2 3 | public abstract class ElectricalTrain extends train { public int maxvoltage (); } |
V 3.0(更改问题3)
钱德问题陈述:你必须为印度铁路创建一个
1 2 3 4 | public abstract class HybridTrain extends ElectricalTrain , DisealTrain { { Not possible in java } } {here Business modeling with abstract class fails} |
2。带接口的业务建模
把
http://javaqna.wordpress.com/2008/08/24/why-the-use-on-interfaces-instead-of-abstract-classes-is-welled-in-java-programming/
接口:如果您的子类都应该实现一组特定的方法/功能,但是每个子类都可以自由地提供自己的实现,那么使用接口。
例如,如果要为车辆实现类层次结构,请实现名为vehicle的接口,该接口具有诸如colour maxspeed等属性和drive()等方法。所有的子类,如汽车滑板车飞机SOLARCAR等,都应该从这个基本接口派生出来,但是提供了一个单独的方法和车辆所暴露的属性的实现。
–>如果希望子类在短时间内实现多个继承中的多个不相关功能,请使用接口。
例如,如果你正在实现一个名为"宇宙飞船"的类,该类必须具有来自车辆和UFO的功能,那么将车辆和UFO作为接口,然后创建一个实现车辆和UFO的类宇宙飞船。
抽象类:
–>当您有一个要求时,您的基类应该提供某些方法的默认实现,而其他方法应该可以被子类覆盖,使用抽象类。
例如,再次以上述车辆类别为例。如果我们希望从vehicle派生的所有类以固定方式实现drive()方法,而其他方法可以被子类重写。在这种情况下,我们将vehicle类实现为一个带有drive实现的抽象类,而将其他方法/属性保留为抽象类,以便它们可以被子类覆盖。
–>抽象类的目的是提供多个派生类可以共享的基类的公共定义。
例如,类库可以定义一个抽象类,该类用作其许多函数的参数,并且要求使用该库的程序员通过创建派生类来提供自己的类实现。
所有其他条件都一样,使用接口。更容易模拟单元测试。
但是,一般来说,我使用基类的目的是当有一些公共代码我宁愿放在一个地方,而不是派生类的每个实例时。如果是像你描述的那样的东西,它们的使用方式是相同的,但是它们的底层机制是不同的,那么界面听起来更合适。
我宁愿选择基本抽象类,因为,理论上(好吧,这只是一个理论,我不是在证明或说任何其他的比这更糟),当你想证明某个对象能够做某些事情(比如,可比较的-你表明无论实现什么,都可以与其他东西相比),当EAS当您有两个实例共享公共内容或有一个逻辑父类时,应该使用抽象类。您也可以使用两种方法,使用基类来实现一个接口,它将显式地指出类可以做什么。
你可以两者兼得。ObjectBase为您省去了多次实现公共属性的麻烦,并为您实现了IObject。无论在何处使用它,都会引用iobject,以便稍后使用mock进行测试。
抽象类的定义可以描述代码和状态,从它们派生的类不能同时从其他类派生。这就是技术差异所在。
因此,从用法和哲学的角度来看,不同之处在于,通过设置抽象类,可以约束该类对象可能实现的任何其他功能,并为这些对象提供任何此类对象所共有的一些基本功能(这也是一种约束),同时通过设置作为一个接口,您不需要为其他功能设置任何约束,也不需要为您所想到的那个功能制定真正的代码规定。当你知道这个类的对象为了用户的利益应该做的所有事情时,使用抽象类。当对象还可能做一些你现在甚至无法猜测的事情时,使用接口。
选择接口和抽象类不是一个非此即彼的命题。如果你需要改变你的设计,把它变成一个界面。但是,您可能拥有提供一些默认行为的抽象类。抽象类是应用程序框架内的优秀候选者。
抽象类允许您定义一些行为;它们强制您的子类提供其他行为。例如,如果您有一个应用程序框架,抽象类可以提供默认服务,如事件和消息处理。这些服务允许应用程序插入应用程序框架。但是,只有应用程序才能执行某些特定于应用程序的功能。此类功能可能包括启动和关闭任务,这些任务通常依赖于应用程序。因此,抽象基类可以声明抽象关闭和启动方法,而不是试图定义该行为本身。基类知道它需要这些方法,但是抽象类允许您的类承认它不知道如何执行这些操作;它只知道它必须启动这些操作。当需要启动时,抽象类可以调用Startup方法。当基类调用此方法时,Java调用由子类定义的方法。
许多开发人员忘记了定义抽象方法的类也可以调用该方法。抽象类是创建计划继承层次结构的一种很好的方法。对于类层次结构中的非叶类,它们也是一个很好的选择。
请注意,不能重写接口中的运算符。就我而言,这是他们唯一真正的问题。
如果您在类中有函数,那么应该使用Abstract类而不是Interface。通常,接口用于代表类型。
我已经在我的项目中使用了抽象类,但在未来的项目中,我将使用接口。"多重继承"的优点非常有用。无论是在代码中还是出于测试目的,都可以提供类的全新实现,这一点一直受到欢迎。最后,如果将来你想让外部开发人员定制你的代码,你不需要给他们你真正的代码-他们只需要使用接口…