一个例子是转发包装类,能够转发到实现I的具体类C的另一个对象,例如启用装饰或C的简单代码重用,而无需从继承C。您可以在 Effective Java 第 16 项中找到这样的示例,优先选择组合而不是继承。 (由于版权原因,我不想将其发布在这里,但它实际上只是将 I 的所有方法调用转发到包装的实现)。
You often have a skeletal implementations for an interface I. If you can offer extensibility without abstract methods (e.g. via hooks), it is preferable to have a non-abstract skeletal class because you can instantiate it.
An example would be a forwarding wrapper classes, to be able to forward to another object of a concrete class C implementing I, e.g. enabling decoration or simple code-reuse of C without having to inherit from C. You can find such an example in Effective Java item 16, favor composition over inheritance. (I do not want to post it here because of copyrights, but it is really simply forwarding all method calls of I to the wrapped implementation).
public class LinkedHashMap<K,V>
extends HashMap<K,V>
另一个很好的例子是异常的继承:
public class IllegalFormatPrecisionException extends IllegalFormatException
public class IllegalFormatException extends IllegalArgumentException
public class IllegalArgumentException extends RuntimeException
public class RuntimeException extends Exception
public class Exception extends Throwable
I think the following is a good example when it can be appropriate:
public class LinkedHashMap<K,V>
extends HashMap<K,V>
Another good example is inheritance of exceptions:
public class IllegalFormatPrecisionException extends IllegalFormatException
public class IllegalFormatException extends IllegalArgumentException
public class IllegalArgumentException extends RuntimeException
public class RuntimeException extends Exception
public class Exception extends Throwable
One very common case I can think of is to derive from basic UI controls, such as forms, textboxes, comboboxes, etc. They are complete, concrete, and well able to stand on their own; however, most of them are also very basic, and sometimes their default behavior isn't what you want. Virtually nobody, for instance, would use an instance of an unadulterated Form, unless possibly they were creating an entirely dynamic UI layer.
For example, in a piece of software I wrote that recently reached relative maturity (meaning I ran out of time to focus primarily on developing it :) ), I found I needed to add "lazy loading" capability to ComboBoxes, so it wouldn't take 50 years (in computer years) for the first window to load. I also needed the ability to automatically filter the available options in one ComboBox based on what was shown in another, and lastly I needed a way to "mirror" one ComboBox's value in another editable control, and make a change in one control happen to the other as well. So, I extended the basic ComboBox to give it these extra features, and created two new types: LazyComboBox, and then further, MirroringComboBox. Both are based on the totally serviceable, concrete ComboBox control, just overriding some behaviors and adding a couple others. They're not very loosely-coupled and therefore not too SOLID, but the added functionality is generic enough that if I had to, I could rewrite either of these classes from scratch to do the same job, possibly better.
Generally speaking, the only time I derive from concrete classes is when they're in the framework. Deriving from Applet or JApplet being the trivial example.
public class AccessToken extends OAuthToken {
/**
*
*/
private static final long serialVersionUID = -4419729971477912556L;
private String accessToken;
private String refreshToken;
private Map<String, String> additionalParameters;
//Getters and setters are here
}
现在,有了返回 token_type 的访问令牌,
public class TokenTypedAccessToken extends AccessToken {
private String tokenType;
//Getter and setter are here...
}
我就可以返回两者和最终用户都一无所知。 :-)
总结: 如果您想要一个与具体类具有相同功能的自定义类,而不更改具体类的结构,我建议扩展具体类。
This is an example of a current implementation that I'm undertaking.
In OAuth 2 environment, since the documentation is still in draft stage, the specification keeps changing (as of time of writing, we're in version 21).
Thus, I had to extend my concrete AccessToken class to accommodate the different access tokens.
In earlier draft, there was no token_type field set, so the actual access token is as follows:
public class AccessToken extends OAuthToken {
/**
*
*/
private static final long serialVersionUID = -4419729971477912556L;
private String accessToken;
private String refreshToken;
private Map<String, String> additionalParameters;
//Getters and setters are here
}
Now, with Access tokens that returns token_type, I have
public class TokenTypedAccessToken extends AccessToken {
private String tokenType;
//Getter and setter are here...
}
So, I can return both and the end user is none the wiser. :-)
In Summary: If you want a customized class that has the same functionality of your concrete class without changing the structure of the concrete class, I suggest extending the concrete class.
I mainly have a Java background, but I'm interested in examples from any language.
Like many frameworks, ASP.NET makes heavy use of inheritance to share behaviour between classes. For example, HtmlInputPassword has this inheritance hierarchy:
The decorator pattern, a handy way of adding additional behaviour to a class without making it too general, makes heavy use of inheritance of concrete classes. It was mentioned here already, but under somewhat a scientific name of "forwarding wrapper class".
public class MBeanRegistrationSupport {
// the concrete class has a hook defined
protected void onRegister(ObjectName objectName) {
}
我们的类:
public class UnregisterableMBeanExporter extends MBeanExporter {
@Override
protected void onUnregister(ObjectName name) {
// always a good idea
super.onRegister(name);
objectMap.remove(name);
}
public class LongType extends LongObjectType {
...
@Override
public boolean isPrimitive() {
return true;
}
}
希望这有帮助。
Lot of answers but I though I'd add my own $0.02.
I override concreate classes infrequently but under some specific circumstances. At least 1 has already been mentioned when framework classes are designed to be extended. 2 additional ones come to mind with some examples:
1) If I want to tweak the behavior of a concrete class. Sometimes I want to change how the concrete class works or I want to know when a certain method is called so I can trigger something. Often concrete classes will define a hook method whose sole usage is for subclasses to override the method.
Example: We overrode MBeanExporter because we need to be able to unregister a JMX bean:
public class MBeanRegistrationSupport {
// the concrete class has a hook defined
protected void onRegister(ObjectName objectName) {
}
Our class:
public class UnregisterableMBeanExporter extends MBeanExporter {
@Override
protected void onUnregister(ObjectName name) {
// always a good idea
super.onRegister(name);
objectMap.remove(name);
}
Here's another good example. LinkedHashMap is designed to have its removeEldestEntry method overridden.
2) If a class shares a significant amount of overlap with the concrete class except for some tweaks to functionality.
Example: My ORMLite project handles persisting Long object fields and long primitive fields. Both have almost the identical definition. LongObjectType provides all of the methods that describe how the database deals with long fields.
public class LongObjectType {
// a whole bunch of methods
while LongType overrides LongObjectType and only tweaks a single method to say that handles primitives.
public class LongType extends LongObjectType {
...
@Override
public boolean isPrimitive() {
return true;
}
}
/* <!-- Defines the applet element used by the appletviewer. -->
<applet code='HelloWorld' width='200' height='100'></applet> */
import javax.swing.*;
/** An 'Hello World' Swing based applet.
To compile and launch:
prompt> javac HelloWorld.java
prompt> appletviewer HelloWorld.java */
public class HelloWorld extends JApplet {
public void init() {
// Swing operations need to be performed on the EDT.
// The Runnable/invokeLater() ensures that happens.
Runnable r = new Runnable() {
public void run() {
// the crux of this simple applet
getContentPane().add( new JLabel("Hello World!") );
}
};
SwingUtilities.invokeLater(r);
}
}
I'm beginning to feel that there is almost no situation where inheriting from a concrete class is appropriate.
This is one 'almost'. Try writing an applet without extending Applet or JApplet.
/* <!-- Defines the applet element used by the appletviewer. -->
<applet code='HelloWorld' width='200' height='100'></applet> */
import javax.swing.*;
/** An 'Hello World' Swing based applet.
To compile and launch:
prompt> javac HelloWorld.java
prompt> appletviewer HelloWorld.java */
public class HelloWorld extends JApplet {
public void init() {
// Swing operations need to be performed on the EDT.
// The Runnable/invokeLater() ensures that happens.
Runnable r = new Runnable() {
public void run() {
// the crux of this simple applet
getContentPane().add( new JLabel("Hello World!") );
}
};
SwingUtilities.invokeLater(r);
}
}
我目前正在开发一个为用户计算矩阵的应用程序。用户可以提供影响计算的设置。可以计算的矩阵有多种类型,但有明显的相似性,特别是在可配置性方面:矩阵 A 可以使用矩阵 B 的所有设置,但具有可以使用的附加参数。在这种情况下,我从 ConfigObjectB 继承了 ConfigObjectA,并且效果非常好。
Another good example would be data storage types. To give a precise example: a red-black tree is a more specific binary tree, but retrieving data and other information like size can be handled identical. Of course, a good library should have that already implemented but sometimes you have to add specific data types for your problem.
I am currently developing an application which calculates matrices for the users. The user can provide settings to influence the calculation. There are several types of matrices that can be calculated, but there is a clear similarity, especially in the configurability: matrix A can use all the settings of matrix B but has additional parameters which can be used. In that case, I inherited from the ConfigObjectB for my ConfigObjectA and it works pretty good.
一般来说,从抽象类继承比从具体类继承更好。具体类必须为其数据表示提供定义,并且某些子类将需要不同的表示。由于抽象类不必提供数据表示形式,因此未来的子类可以使用任何表示形式,而不必担心与它们继承的表示形式发生冲突。
即使我也从未发现过需要具体继承的情况。但在某些情况下可能需要具体继承,特别是当您为软件提供向后兼容性时。在这种情况下,您可能已经专门化了一个 A 类,但您希望它是具体的,因为您的旧应用程序可能正在使用它。
In general, it is better to inherit from an abstract class than from a concrete class. A concrete class must provide a definition for its data representation, and some subclasses will need a different representation. Since an abstract class does not have to provide a data representation, future subclasses can use any representation without fear of conflicting with the one that they inherited.
Even i never found a situation where i felt concrete inheritence is neccessary. But there could be some situations for concrete inheritence specially when you are providing backward compatibility to your software. In that case u might have specialized a class A but you want it to be concrete as your older application might be using it.
[编辑] 我将通过说当您控制架构时我看不到它的良好用例来限定此声明。当然,当使用需要它的 API 时,该怎么办?但我不明白这些 API 所做的设计选择。调用类应该始终能够根据依赖倒置原则声明和使用抽象。如果子类有其他要使用的接口,您要么必须违反 DIP,要么进行一些丑陋的转换才能获取这些接口。
Your concerns are also echoed in the classic principle "favor composition over inheritance", for the reasons you stated. I can't remember the last time I inherited from a concrete class. Any common code that needs to be reused by child classes almost always needs to declare abstract interfaces for those classes. In this order I try to prefer the following strategies:
Composition (no inheritance)
Interface
Abstract Class
Inheriting from a concrete class really isn't ever a good idea.
[EDIT] I'll qualify this statement by saying I don't see a good use case for it when you have control over the architecture. Of course when using an API that expects it, whaddaya gonna do? But I don't understand the design choices made by those APIs. The calling class should always be able to declare and use an abstraction according to the Dependency Inversion Principle. If a child class has additional interfaces to be consumed you'd either have to violate DIP or do some ugly casting to get at those interfaces.
com.google.gdata.client.Service is designed to act as a base class that can be customized for specific types of GData services.
Service javadoc:
The Service class represents a client connection to a GData service. It encapsulates all protocol-level interactions with the GData server and acts as a helper class for higher level entities (feeds, entries, etc) that invoke operations on the server and process their results.
This class provides the base level common functionality required to access any GData service. It is also designed to act as a base class that can be customized for specific types of GData services. Examples of supported customizations include:
Authentication - implementing a custom authentication mechanism for services that require authentication and use something other than HTTP basic or digest authentication.
Extensions - define expected extensions for feed, entry, and other types associated with a the service.
Formats - define additional custom resource representations that might be consumed or produced by the service and client side parsers and generators to handle them.
I find the java collection classes as a very good example.
So you have an AbstractCollection with childs like AbstractList, AbstractSet, AbstractQueue...
I think this hierarchy has been well designed.. and just to ensure there's no explosion there's the Collections class with all its inner static classes.
You do that for instance in GUI libraries. It makes not much sense to inherit from a mere Component and delegate to a Panel. It is likely much easyer to inherit from the Panel directly.
Just a general thought. Abstract classes are missing something. It makes sense if this, what is missing, is different in each derived class. But you may have a case where you don't want to modify a class but just want to add something. To avoid duplication of code you would inherit. And if you need both classes it would be inheritance from a concrete class.
So my answer would be: In all cases where you really only want to add something. Maybe this just doesn't happen very often.
发布评论
评论(18)
您通常有一个接口
I
的骨架实现。如果您可以在没有抽象方法的情况下提供可扩展性(例如通过钩子),那么最好有一个非抽象骨架类,因为您可以实例化它。一个例子是转发包装类,能够转发到实现
I
的具体类C
的另一个对象,例如启用装饰或C
的简单代码重用,而无需从继承C。您可以在 Effective Java 第 16 项中找到这样的示例,优先选择组合而不是继承。 (由于版权原因,我不想将其发布在这里,但它实际上只是将
I
的所有方法调用转发到包装的实现)。You often have a skeletal implementations for an interface
I
. If you can offer extensibility without abstract methods (e.g. via hooks), it is preferable to have a non-abstract skeletal class because you can instantiate it.An example would be a forwarding wrapper classes, to be able to forward to another object of a concrete class
C
implementingI
, e.g. enabling decoration or simple code-reuse ofC
without having to inherit fromC
. You can find such an example in Effective Java item 16, favor composition over inheritance. (I do not want to post it here because of copyrights, but it is really simply forwarding all method calls ofI
to the wrapped implementation).我认为以下是一个合适的例子:
另一个很好的例子是异常的继承:
I think the following is a good example when it can be appropriate:
Another good example is inheritance of exceptions:
我能想到的一种非常常见的情况是从基本的 UI 控件派生,例如表单、文本框、组合框等。它们是完整的、具体的,并且能够独立存在;然而,它们中的大多数也非常基本,有时它们的默认行为并不是您想要的。例如,几乎没有人会使用纯粹的 Form 实例,除非他们可能正在创建一个完全动态的 UI 层。
例如,在我编写的一个最近达到相对成熟的软件中(这意味着我没有时间主要专注于开发它:)),我发现我需要向 ComboBox 添加“延迟加载”功能,因此它不会第一个窗口加载需要 50 年(以计算机年为单位)。我还需要能够根据另一个组合框中显示的内容自动筛选一个组合框中的可用选项,最后,我需要一种方法将一个组合框的值“镜像”到另一个可编辑控件中,并使一个控件中的更改发生在另一个可编辑控件中。其他也一样。因此,我扩展了基本的 ComboBox 以赋予它这些额外的功能,并创建了两种新类型:LazyComboBox,然后是 MirroringComboBox。两者都基于完全可用的具体 ComboBox 控件,只是覆盖一些行为并添加其他一些行为。它们不是非常松散耦合,因此不太坚固,但添加的功能足够通用,如果必须的话,我可以从头开始重写这些类中的任何一个来完成相同的工作,甚至可能更好。
One very common case I can think of is to derive from basic UI controls, such as forms, textboxes, comboboxes, etc. They are complete, concrete, and well able to stand on their own; however, most of them are also very basic, and sometimes their default behavior isn't what you want. Virtually nobody, for instance, would use an instance of an unadulterated Form, unless possibly they were creating an entirely dynamic UI layer.
For example, in a piece of software I wrote that recently reached relative maturity (meaning I ran out of time to focus primarily on developing it :) ), I found I needed to add "lazy loading" capability to ComboBoxes, so it wouldn't take 50 years (in computer years) for the first window to load. I also needed the ability to automatically filter the available options in one ComboBox based on what was shown in another, and lastly I needed a way to "mirror" one ComboBox's value in another editable control, and make a change in one control happen to the other as well. So, I extended the basic ComboBox to give it these extra features, and created two new types: LazyComboBox, and then further, MirroringComboBox. Both are based on the totally serviceable, concrete ComboBox control, just overriding some behaviors and adding a couple others. They're not very loosely-coupled and therefore not too SOLID, but the added functionality is generic enough that if I had to, I could rewrite either of these classes from scratch to do the same job, possibly better.
一般来说,我唯一一次从具体类派生是当它们位于框架中时。派生自
Applet
或JApplet
是一个简单的例子。Generally speaking, the only time I derive from concrete classes is when they're in the framework. Deriving from
Applet
orJApplet
being the trivial example.这是我当前正在实施的一个示例。
在 OAuth 2 环境中,由于文档仍处于草案阶段,因此规范不断变化(截至撰写本文时,我们处于版本 21)。
因此,我必须扩展具体的
AccessToken
类以适应不同的访问令牌。在早期的草案中,没有设置
token_type
字段,因此实际的访问令牌如下:现在,有了返回
token_type
的访问令牌,我就可以返回两者和最终用户都一无所知。 :-)
总结: 如果您想要一个与具体类具有相同功能的自定义类,而不更改具体类的结构,我建议扩展具体类。
This is an example of a current implementation that I'm undertaking.
In OAuth 2 environment, since the documentation is still in draft stage, the specification keeps changing (as of time of writing, we're in version 21).
Thus, I had to extend my concrete
AccessToken
class to accommodate the different access tokens.In earlier draft, there was no
token_type
field set, so the actual access token is as follows:Now, with Access tokens that returns
token_type
, I haveSo, I can return both and the end user is none the wiser. :-)
In Summary: If you want a customized class that has the same functionality of your concrete class without changing the structure of the concrete class, I suggest extending the concrete class.
与许多框架一样,ASP.NET 大量使用继承来在类之间共享行为。例如, HtmlInputPassword 具有以下继承层次结构
:可以看到具体类的派生示例。
如果您正在构建一个框架 - 并且您确定想要这样做 - 您可能会发现自己需要一个漂亮的大继承层次结构。
Like many frameworks, ASP.NET makes heavy use of inheritance to share behaviour between classes. For example, HtmlInputPassword has this inheritance hierarchy:
in which can be seen examples of concrete classes being derived from.
If you're building a framework - and you're sure you want to do that - you may well finding yourself wanting a nice big inheritance hierarchy.
其他用例是覆盖默认行为:
假设有一个类使用标准 Jaxb 解析器进行解析
现在假设我想使用一些不同的绑定(比如 XMLBean)进行解析操作,
现在我可以使用新的绑定与超类的代码重用。
Other use case would be the to override the default behavior:
Lets say there is a class which uses standard Jaxb parser for parsing
Now say I want to use some different binding (Say XMLBean) for the parsing operation,
Now I can use the new binding with code reuse of super class.
装饰器模式是一种向类添加额外行为而不使其过于通用的便捷方法,使得大量使用具体类的继承。这里已经提到过,但在某种程度上是“转发包装类”的科学名称。
The decorator pattern, a handy way of adding additional behaviour to a class without making it too general, makes heavy use of inheritance of concrete classes. It was mentioned here already, but under somewhat a scientific name of "forwarding wrapper class".
有很多答案,但我想我自己加 0.02 美元。
我很少重写 concreate 类,但在某些特定情况下。当框架类被设计为可扩展时,至少已经提到了 1。我想到了另外两个例子:
1)如果我想调整具体类的行为。有时我想更改具体类的工作方式,或者我想知道何时调用某个方法,以便我可以触发某些内容。通常,具体类会定义一个钩子方法,其唯一用途是让子类重写该方法。
示例:我们重写了
MBeanExporter
,因为我们需要能够取消注册 JMX bean:我们的类:
这是另一个很好的示例。
LinkedHashMap
被设计为具有其removeEldestEntry
方法已被重写。2) 如果一个类与具体类有大量重叠,除了对功能进行一些调整之外。
示例:我的 ORMLite 项目处理持久的
Long
对象字段和long
原始领域。两者的定义几乎相同。LongObjectType
提供了描述数据库如何处理的所有方法长
字段。而
LongObjectType
并且只调整一个方法来处理基元。希望这有帮助。
Lot of answers but I though I'd add my own $0.02.
I override concreate classes infrequently but under some specific circumstances. At least 1 has already been mentioned when framework classes are designed to be extended. 2 additional ones come to mind with some examples:
1) If I want to tweak the behavior of a concrete class. Sometimes I want to change how the concrete class works or I want to know when a certain method is called so I can trigger something. Often concrete classes will define a hook method whose sole usage is for subclasses to override the method.
Example: We overrode
MBeanExporter
because we need to be able to unregister a JMX bean:Our class:
Here's another good example.
LinkedHashMap
is designed to have itsremoveEldestEntry
method overridden.2) If a class shares a significant amount of overlap with the concrete class except for some tweaks to functionality.
Example: My ORMLite project handles persisting
Long
object fields andlong
primitive fields. Both have almost the identical definition.LongObjectType
provides all of the methods that describe how the database deals withlong
fields.while
LongType
overridesLongObjectType
and only tweaks a single method to say that handles primitives.Hope this helps.
如果您想扩展辅助库功能,则只能选择继承具体类。
对于现实生活中的使用示例,您可以查看 DataInputStream 的层次结构
Inheriting concrete class is only option if you want to extend side-library functionality.
For example of real life usage you can look at hierarchy of DataInputStream, that implements DataInput interface for FilterInputStream.
这就是“几乎”了。尝试编写一个 applet 而不扩展
Applet< /code> 或
JApplet
。这是来自 小程序信息的示例。页面。
This is one 'almost'. Try writing an applet without extending
Applet
orJApplet
.Here is an e.g. from the applet info. page.
另一个很好的例子是数据存储类型。举一个精确的例子:红黑树是一种更具体的二叉树,但是检索数据和其他信息(例如大小)可以进行相同的处理。当然,一个好的库应该已经实现,但有时您必须为您的问题添加特定的数据类型。
我目前正在开发一个为用户计算矩阵的应用程序。用户可以提供影响计算的设置。可以计算的矩阵有多种类型,但有明显的相似性,特别是在可配置性方面:矩阵 A 可以使用矩阵 B 的所有设置,但具有可以使用的附加参数。在这种情况下,我从 ConfigObjectB 继承了 ConfigObjectA,并且效果非常好。
Another good example would be data storage types. To give a precise example: a red-black tree is a more specific binary tree, but retrieving data and other information like size can be handled identical. Of course, a good library should have that already implemented but sometimes you have to add specific data types for your problem.
I am currently developing an application which calculates matrices for the users. The user can provide settings to influence the calculation. There are several types of matrices that can be calculated, but there is a clear similarity, especially in the configurability: matrix A can use all the settings of matrix B but has additional parameters which can be used. In that case, I inherited from the ConfigObjectB for my ConfigObjectA and it works pretty good.
一般来说,从抽象类继承比从具体类继承更好。具体类必须为其数据表示提供定义,并且某些子类将需要不同的表示。由于抽象类不必提供数据表示形式,因此未来的子类可以使用任何表示形式,而不必担心与它们继承的表示形式发生冲突。
即使我也从未发现过需要具体继承的情况。但在某些情况下可能需要具体继承,特别是当您为软件提供向后兼容性时。在这种情况下,您可能已经专门化了一个
A 类
,但您希望它是具体的,因为您的旧应用程序可能正在使用它。In general, it is better to inherit from an abstract class than from a concrete class. A concrete class must provide a definition for its data representation, and some subclasses will need a different representation. Since an abstract class does not have to provide a data representation, future subclasses can use any representation without fear of conflicting with the one that they inherited.
Even i never found a situation where i felt concrete inheritence is neccessary. But there could be some situations for concrete inheritence specially when you are providing backward compatibility to your software. In that case u might have specialized a
class A
but you want it to be concrete as your older application might be using it.由于您所说的原因,您的担忧也在经典原则“优先考虑组合而不是继承”中得到了回应。我不记得上次从具体类继承是什么时候了。任何需要被子类重用的公共代码几乎总是需要为这些类声明抽象接口。按照这个顺序,我尝试更喜欢以下策略:
从具体类继承确实不是一个好主意。
[编辑] 我将通过说当您控制架构时我看不到它的良好用例来限定此声明。当然,当使用需要它的 API 时,该怎么办?但我不明白这些 API 所做的设计选择。调用类应该始终能够根据依赖倒置原则声明和使用抽象。如果子类有其他要使用的接口,您要么必须违反 DIP,要么进行一些丑陋的转换才能获取这些接口。
Your concerns are also echoed in the classic principle "favor composition over inheritance", for the reasons you stated. I can't remember the last time I inherited from a concrete class. Any common code that needs to be reused by child classes almost always needs to declare abstract interfaces for those classes. In this order I try to prefer the following strategies:
Inheriting from a concrete class really isn't ever a good idea.
[EDIT] I'll qualify this statement by saying I don't see a good use case for it when you have control over the architecture. Of course when using an API that expects it, whaddaya gonna do? But I don't understand the design choices made by those APIs. The calling class should always be able to declare and use an abstraction according to the Dependency Inversion Principle. If a child class has additional interfaces to be consumed you'd either have to violate DIP or do some ugly casting to get at those interfaces.
来自 gdata 项目:
com.google.gdata.client.Service 旨在充当基类,可以针对特定类型的 GData 服务进行定制。
Service javadoc:
Service 类表示与 GData 服务的客户端连接。它封装了与 GData 服务器的所有协议级交互,并充当更高级别实体(提要、条目等)的帮助程序类,这些实体调用服务器上的操作并处理其结果。
此类提供访问任何 GData 服务所需的基本级别通用功能。它还被设计为充当基类,可以针对特定类型的 GData 服务进行自定义。 支持的自定义示例包括:
身份验证 - 为需要身份验证并使用 HTTP 基本或摘要身份验证以外的内容的服务实现自定义身份验证机制。
扩展 - 定义与服务关联的提要、条目和其他类型的预期扩展。
格式 - 定义可能由服务和客户端解析器和生成器使用或生成的其他自定义资源表示形式来处理它们。
from the gdata project:
com.google.gdata.client.Service is designed to act as a base class that can be customized for specific types of GData services.
Service javadoc:
The Service class represents a client connection to a GData service. It encapsulates all protocol-level interactions with the GData server and acts as a helper class for higher level entities (feeds, entries, etc) that invoke operations on the server and process their results.
This class provides the base level common functionality required to access any GData service. It is also designed to act as a base class that can be customized for specific types of GData services. Examples of supported customizations include:
Authentication - implementing a custom authentication mechanism for services that require authentication and use something other than HTTP basic or digest authentication.
Extensions - define expected extensions for feed, entry, and other types associated with a the service.
Formats - define additional custom resource representations that might be consumed or produced by the service and client side parsers and generators to handle them.
我发现 java 集合类是一个很好的例子。
所以你有一个 AbstractCollection 和像 AbstractList、AbstractSet、AbstractQueue 这样的子项...
我认为这个层次结构设计得很好……为了确保不会发生爆炸,有 Collections 类及其所有内部静态类。
I find the java collection classes as a very good example.
So you have an AbstractCollection with childs like AbstractList, AbstractSet, AbstractQueue...
I think this hierarchy has been well designed.. and just to ensure there's no explosion there's the Collections class with all its inner static classes.
例如,您可以在 GUI 库中执行此操作。从单纯的组件继承并委托给面板没有多大意义。直接从Panel 继承可能要容易得多。
You do that for instance in GUI libraries. It makes not much sense to inherit from a mere Component and delegate to a Panel. It is likely much easyer to inherit from the Panel directly.
只是一个一般的想法。抽象类缺少一些东西。如果每个派生类中缺少的内容都不同,那就有意义了。但您可能会遇到这样的情况:您不想修改类,而只想添加一些内容。为了避免重复代码,您将继承。如果您需要这两个类,那么它将是从具体类的继承。
所以我的答案是:在所有情况下,你真的只想添加一些东西。也许这种情况并不经常发生。
Just a general thought. Abstract classes are missing something. It makes sense if this, what is missing, is different in each derived class. But you may have a case where you don't want to modify a class but just want to add something. To avoid duplication of code you would inherit. And if you need both classes it would be inheritance from a concrete class.
So my answer would be: In all cases where you really only want to add something. Maybe this just doesn't happen very often.