Adapters and Functional Abstraction
I can’t decide what I think about the following implementation so I decided to throw it out here. Any thoughts are welcome.
In a previous post I wrote about our wrapper around Bouncy Castle PGP encryption. Turned out it worked pretty well except one little problem. The PGP implementation on the receiving end would complain about our signature. In despair I even posted (and later answered) a question on StackOverflow. :-)
The problem was that they use an old version of a PGP library that couldn’t deal with our newer v4 signatures. Oh, forget it, I’m not going to bore you with the details…
I looked at the code for creating the object that does the signing and it returns an instance of a PgpSignatureGenerator (A Bouncy Castle class). Instead of using this signature generator we needed to use a PgpV3SignatureGenerator (Also a Bouncy Castle class). It was no big deal to change the code to instantiate and return a different type. However, we wanted to be able to return the v4 signature generator as well. Since both PgpSignatureGenerator and PgpV3SignatureGenerator are concrete implementations without a common base class we could not just return a common abstraction. Ok, still not a big deal. We can just create a wrapper (adapter) around the implementations and return that.
That’s when you’re hit by the principle/rule police. SOLID, good? SOLID bad? should you prefer composition over inheritance or use a inheritance based version of the adapter pattern. Oh no, is this Adapter or is it Facade? … Just kidding…
But I couldn’t resist it after the last couple of weeks of noise around principles and rules and whether they’re good or not.
After a closer look at the two classes, I saw that they conform to the same interface (for the parts relevant to us at least). So I decided to skip over any design pattern I knew of and just take the shortest path to a solution that works. We need to make two calls on the signature generator while encrypting. This is after the initial setup of the signature generator. You can see the two signatures below. For this discussion it doesn’t matter what they accomplish.
public void Update(byte[] buffer, int offset, int length);
public PgpSignature Generate();
The following class captures this functionality and the caller doesn’t know at the time of calling the methods whether it’s a v4 or v3 signature.
public class Signer
{ public Action<byte[], int, int> Update { get; set; } public Func<PgpSignature> Generate { get; set; }}
Signer can now be instantiated with either a v3 or v4 signature generator.
public Signer GetSignatureGenerator(Stream compressedOut,
SignatureVersion signatureVersion)
{ if (signatureVersion == SignatureVersion.V3)
{ PgpV3SignatureGenerator pgpV3SignatureGenerator =
new PgpV3SignatureGenerator(...);
// some more initialization code
return new Signer
{ Update = (data, offset, length) => pgpV3SignatureGenerator.Update(data, offset, length),
Generate = () => pgpV3SignatureGenerator.Generate()
};
}
else if (signatureVersion == SignatureVersion.V4)
{ PgpSignatureGenerator pgpSignatureGenerator =
new PgpSignatureGenerator(...);
// some more initialization code
pgpSignatureGenerator.GenerateOnePassVersion(false).Encode(compressedOut);
return new Signer
{ Update = (data, offset, length) => pgpSignatureGenerator.Update(data, offset, length),
Generate = () => pgpSignatureGenerator.Generate()
};
}
else
{ throw new ArgumentException("Invalid signature version"); }
}
You can get a v3 signature generator by using the following.
var signer = GetSignatureGenerator(compressedOut, SignatureVersion.V3);
While it might not be entirely idiomatic to encapsulate by capturing only the behavior of the adaptee, I kind of like the minimalistic approach. It migth break in more complex scenarios without a common interface, but for the simple stuff I think I like it.
So what do you think?
Nice? Ugly? other?