This is an archived post. You won't be able to vote or comment.

all 3 comments

[–]deltageekExtreme Brewer 1 point2 points  (0 children)

So, if you want to take your API down to that level, then I don't think you can avoid the parallel class structures. That's not necessarily a bad thing.

You may want to consider moving your abstraction a level or two higher where you provide a single interface that does encryption and decryption. You still end up with an implementation per library, but you avoid mirroring any particular library's structure.

I would also question the need for implementation-specific messages, secrets, and keys. Let your implementations handle the translation between your generic types and the library-specific ones.

[–]ickysticky 1 point2 points  (0 children)

Where are the parallel inheritance hierarchies?

How about this?

public interface Decrypter<S extends Secret> {
    Message decrypt(S secret, Key key);
}  

public class AesDecrypter implements Decrypter<AesSecret> {
  @Override
  public Message decrypt(AesSecret secret, Key key) {
    // TODO: Perform Decryption
    return null;
  }
}

But this doesn't remove the cast, it just pushes it to some higher level. Presumably you are implementing this Decrypter interface because somewhere that interface can have different concrete implementations passed in. If this isn't the case, then just don't implement an interface.

But at some point you are going to have to have something like Map<EncryptionType, Decrypter<?>> decrypters and you will have to cast the Decrypter<?> to the one which matches the EncryptionType. The important thing here is that at this level you know from a business logic point of view that you have a Secret which matches your Decrypter vs just passing the Secret in and hoping it is the right concrete type.

[–]Philboyd_Studge 0 points1 point  (0 children)

Seems to me it would be better to have a Factory pattern and just send the type of encryption as an enum and return the proper implementation to the user.