質問を明確にするためにこの例を思いつきました
基本クラスから始めます
/// <summary>
/// Just a silly example class
/// </summary>
class CFileStream
{
    protected readonly string FilePath;
    public CFileStream(string filePath)
    {
        FilePath = filePath;
    }
    public virtual void Write(string s)
    {
        var stream = GetStream(FilePath);
        //etc
    }
    /// <summary>
    /// Take filePath as an argument to make subclassing easier
    /// </summary>
    protected virtual FileStream GetStream(string filePath)
    {
        return new FileStream(filePath, FileMode.OpenOrCreate);
    }
}
そのサブクラスを作成します
/// <summary>
/// Building on top of CFileStream, created an encrypted version
/// </summary>
class CFileStreamEncrypted : CFileStream
{
    private readonly string _key;
    public CFileStreamEncrypted(string filePath, string key):base(filePath)
    {
        _key = key;
    }
    /// <summary>
    /// For added complexity, let's also wrap a possible excepton
    /// </summary>
    public override void Write(string s)
    {
        try
        {
            base.Write(s);
        }
        catch (ImaginaryCryptoException ex)
        {
            throw new ImaginaryCustomException("bladibla", ex);
        }
    }
    /// <summary>
    /// Wrap the base stream in an imaginary crypto class
    /// </summary>
    protected override FileStream GetStream(string filePath)
    {
        return new CImaginaryCryptoStream(base.GetStream(filePath), _key);
    }
}
ここで、2 番目のサブクラスを作成しますが、これは最初のファイルライターと暗号化されたバージョンで動作します。
最初のものは理にかなっている
/// <summary>
/// Building on top of CFileStream, created an auto-split version
/// </summary>
class CFileStreamSplit : CFileStream
{
    public CFileStreamSplit(string filePath) 
        : base(filePath)
    {
    }
    protected int Counter;
    /// <summary>
    /// Close stream and move to next file at the appropriate time(s)
    /// </summary>
    public override void Write(string s)
    {
        do
        {
            Stream stream;
            if (ImaginaryBooleanMustSplit)
                stream = GetStream(FilePath);
            //etc
        } while (ImaginaryBooleanDataLeftToWrite);
    }
    /// <summary>
    /// Get base stream but with altered filePath
    /// </summary>
    protected override FileStream GetStream(string filePath)
    {
        return base.GetStream(GetNextpath(filePath));
    }
    /// <summary>
    /// Ignore proper extension / file-exists etc.
    /// </summary>
    protected virtual string GetNextpath(string filePath)
    {
        return filePath + ++Counter;
    }
}
2 つ目 (この下) は、暗号化キーも必要とするコンストラクターを除いて、完全に重複したコードです。
/// <summary>
/// Build the same auto-split version but this time on top of the encrypted subclass
/// </summary>
class CFileStreamSplitEncrypted : CFileStreamEncrypted
{
    public CFileStreamSplitEncrypted(string filePath, string key)
        : base(filePath, key)
    {
    }
    /*
     * Note that there are no changes below this line
     */
    protected int Counter;
    /// <summary>
    /// Close stream and move to next file at the appropriate time(s)
    /// </summary>
    public override void Write(string s)
    {
        do
        {
            Stream stream;
            if (ImaginaryBooleanMustSplit)
                stream = GetStream(FilePath);
            //etc
        } while (ImaginaryBooleanDataLeftToWrite);
    }
    /// <summary>
    /// Get base stream but with altered filePath
    /// </summary>
    protected override FileStream GetStream(string filePath)
    {
        return base.GetStream(GetNextpath(filePath));
    }
    /// <summary>
    /// Ignore proper extension / file-exists etc.
    /// </summary>
    protected virtual string GetNextpath(string filePath)
    {
        return filePath + ++Counter;
    }
}
もちろん、ここで重複コードの量を減らす方法はたくさんありますが、そのようなことがあったとしても、「最善の」方法をまだ見つけていません。そう; あなたの意見/経験において、この問題を回避するための最も時間がかからず、最もクリーンで、最も柔軟な方法は何ですか?