Extract Superclass
Before you begin: Classes, inheritance, constructors, and shared behavior.
Extract Superclass creates a common base class for existing classes that share a genuine contract and implementation. Common fields and methods move into that base, while specialized features remain in the original classes. 1
Original version: two asset types repeat their common identity
An editor manages image and audio assets. Both have a name and use the same browser label.
public sealed class ImageAsset
{
private readonly string name;
public ImageAsset(string name) { this.name = name; }
public string Label() { return "Asset: " + name; }
}
public sealed class AudioAsset
{
private readonly string name;
public AudioAsset(string name) { this.name = name; }
public string Label() { return "Asset: " + name; }
}class ImageAsset:
def __init__(self, name):
self._name = name
def label(self):
return "Asset: " + self._name
class AudioAsset:
def __init__(self, name):
self._name = name
def label(self):
return "Asset: " + self._nameThe duplicated code represents the same editor concept: a named asset that can supply a label. That shared meaning matters more than the similar syntax.
Refactored version: make the asset contract explicit
public abstract class Asset
{
private readonly string name;
protected Asset(string name) { this.name = name; }
public string Label() { return "Asset: " + name; }
}
public sealed class ImageAsset : Asset
{
public ImageAsset(string name) : base(name) { }
}
public sealed class AudioAsset : Asset
{
public AudioAsset(string name) : base(name) { }
}class Asset:
def __init__(self, name):
self._name = name
def label(self):
return "Asset: " + self._name
class ImageAsset(Asset):
pass
class AudioAsset(Asset):
passBoth types inherit one initialization and labeling implementation. A browser can work with the common asset capability without knowing whether it is displaying an image or audio item.
Similar code does not always imply a shared parent
If two classes merely happen to format strings similarly, a helper function may be sufficient. If they share a capability but not implementation, an interface can express that contract without imposing shared storage or a base constructor.
A base class also creates coupling: changes to common initialization or behavior can affect all subclasses. Keep image-specific decoding and audio-specific playback out of the shared base unless every asset truly supports the same contract.
The example omits those specialized features to isolate the extraction itself. In a production hierarchy, verify that inherited behavior remains valid for every subtype and that existing callers retain their expected results.