c# - Subclassing all classes in a 'chain' of subclasses -
i came example clarify question
we start base class
/// <summary> /// 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 argument make subclassing easier /// </summary> protected virtual filestream getstream(string filepath) { return new filestream(filepath, filemode.openorcreate); } }
create subclass it
/// <summary> /// building on top of cfilestream, created encrypted version /// </summary> class cfilestreamencrypted : cfilestream { private readonly string _key; public cfilestreamencrypted(string filepath, string key):base(filepath) { _key = key; } /// <summary> /// added complexity, let's wrap possible excepton /// </summary> public override void write(string s) { try { base.write(s); } catch (imaginarycryptoexception ex) { throw new imaginarycustomexception("bladibla", ex); } } /// <summary> /// wrap base stream in imaginary crypto class /// </summary> protected override filestream getstream(string filepath) { return new cimaginarycryptostream(base.getstream(filepath), _key); } }
now wish create second subclass, 1 works initial filewriter encrypted version.
the first 1 makes sense
/// <summary> /// building on top of cfilestream, created auto-split version /// </summary> class cfilestreamsplit : cfilestream { public cfilestreamsplit(string filepath) : base(filepath) { } protected int counter; /// <summary> /// close stream , move next file @ appropriate time(s) /// </summary> public override void write(string s) { { stream stream; if (imaginarybooleanmustsplit) stream = getstream(filepath); //etc } while (imaginarybooleandatalefttowrite); } /// <summary> /// base stream 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; } }
the second 1 (below this) duplicate code, except constructor requires encryption key.
/// <summary> /// build same auto-split version time on top of encrypted subclass /// </summary> class cfilestreamsplitencrypted : cfilestreamencrypted { public cfilestreamsplitencrypted(string filepath, string key) : base(filepath, key) { } /* * note there no changes below line */ protected int counter; /// <summary> /// close stream , move next file @ appropriate time(s) /// </summary> public override void write(string s) { { stream stream; if (imaginarybooleanmustsplit) stream = getstream(filepath); //etc } while (imaginarybooleandatalefttowrite); } /// <summary> /// base stream 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; } }
there of course lot of ways reduce amount of duplicate code here, have yet find 'the best' way, if there such thing. so; least time-consuming, cleanest, flexible way round issue in opinion/experience?
for different modifications decent way go may composition on inheritance. set classes responsible single thing, taking in base stream on constructions.
interface icfilestream { void write(string s); filestream getstream(string filepath); } /// <summary> /// silly example class /// </summary> class cfilestream: icfilestream { protected readonly string filepath; public cfilestream(string filepath) { filepath = filepath; } public void write(string s) { var stream = getstream(filepath); //etc } /// <summary> /// take filepath argument make subclassing easier /// </summary> protected filestream getstream(string filepath) { return new filestream(filepath, filemode.openorcreate); } } /// <summary> /// building on top of cfilestream, created encrypted version /// </summary> class cfilestreamencrypted : icfilestream { private readonly string _key; private readonly icfilestream _stream; public cfilestreamencrypted(string key, icfilestream stream) { _key = key; _stream = stream; } /// <summary> /// added complexity, let's wrap possible excepton /// </summary> public void write(string s) { try { _stream.write(s); } catch (imaginarycryptoexception ex) { throw new imaginarycustomexception("bladibla", ex); } } /// <summary> /// wrap base stream in imaginary crypto class /// </summary> protected filestream getstream(string filepath) { return new cimaginarycryptostream(_stream.getstream(filepath), _key); } } class cfilestreamsplit : icfilestream { private readonly icfilestream _stream; public cfilestreamsplit(icfilestream stream) { _stream = stream; } protected int counter; /// <summary> /// close stream , move next file @ appropriate time(s) /// </summary> public void write(string s) { { stream stream; if (imaginarybooleanmustsplit) stream = getstream(filepath); //etc } while (imaginarybooleandatalefttowrite); } /// <summary> /// base stream altered filepath /// </summary> protected filestream getstream(string filepath) { return _stream.getstream(getnextpath(filepath)); } /// <summary> /// ignore proper extension / file-exists etc. /// </summary> protected string getnextpath(string filepath) { return filepath + ++counter; } }
so when want splitting-crypto-filestream:
new cfilestreamsplit(new cfilestreamencrypted("crypto-awesome-key", new cfilestream("c:\\blah...")));
this more flexible when want add loggingcfilestream example don't need add separate class each combination.
Comments
Post a Comment