2

Currently I'm busy with implement the Factory Pattern into my Java Code. I've got these classes:

CipherStorage

public class CipherStorage {

    protected String transformation;
    protected String provider;
    protected String providerPair;

    public CipherStorage(String transformation, String provider, String providerPair){
        this.transformation = transformation;
        this.provider = provider;
        this.providerPair = providerPair;
    }
}

CipherStorageProcessor (Interface)

public interface CipherStorageProcessor {
    byte[] encryptData(String keyName, String input, @Nullable SharedPreferences pref);
    byte[] decryptData(String keyName, byte[] encrypted, @Nullable SharedPreferences pref);
}

CipherStorageRSA

public class CipherStorageRSA extends CipherStorage implements CipherStorageProcessor {

    public CipherStorageRSA(String transformation, String provider,String providerPair){
        super(transformation, provider, providerPair);
    }
}

CipherStorageAES

public class CipherStorageAES extends CipherStorage implements CipherStorageProcessor {

    public CipherStorageAES(String transformation, String provider, String providerPair){
        super(transformation, provider, providerPair);
    }
}

CipherStorageFactory

public class CipherStorageFactory {

    public CipherStorage getCipher(String cipherType) {
        if (cipherType == null) {
            return null;
        }
        if (cipherType.equalsIgnoreCase("AES")) {
            return new CipherStorageAES();

        } else if (cipherType.equalsIgnoreCase("RSA")) {
            return new CipherStorageRSA();

        }
    }
}

Is this code made any sense? Is it correct to add parameters into the factory? Is there an better way to this?

Already thanks for any help.

PS: i removed the two interface functions from the classes to prevent a lot of code.

EDIT:

When i create an instance of RSA for example:

CipherStorage RSA = CipherStorageFactory.getCipher("RSA");

I've got no access to the methods into the interface?

8
  • Yeah, it is correct as per standards. Commented Jan 10, 2019 at 13:06
  • @Comman Man, Thanks for the answer. In the factory i must add the constructor parameters ? for example return new CipherStorageRSA('transformation', 'provider', providerPair)? Commented Jan 10, 2019 at 13:08
  • @Yakalent If the parameters have the same semantics for all products adding them to the factory method is fine by me. Commented Jan 10, 2019 at 13:09
  • 2
    You could make the factory method static so that you don't need to create instances of the factory. Passing parameters into the factory method is totally fine since you need something to distinguish which subclass to create. Commented Jan 10, 2019 at 13:09
  • @leftbit Ok, sorry for my unclear question but what is the best way to do this? must it be hardcoded parameters or what is the other option? Commented Jan 10, 2019 at 13:14

2 Answers 2

2
  1. Regarding Factory Pattern

Your implementation of the factory pattern is correct.

Regarding constructor parameters of your concrete classes, you can preconfigure them into your factory object(as those parameters are common throughout different cipher objects that the factory creates), and use them to create instances within your factory method:

public class CipherStorageFactory {
    private String transformation;
    private String provider;
    private String providerPair;

    public CipherStorageFactory(String transformation, String provider, String providerPair){
        this.transformation = transformation;
        this.provider = provider;
        this.providerPair = providerPair;
    }

    public CipherStorage getCipher(String cipherType) {
        //...
        if (cipherType.equalsIgnoreCase("AES")) {
            return new CipherStorageAES(transformation, provider, providerPair);
        } else 
        //...
    }
}

Additionally, in this case, it is better to name your factory method like "createCipher()", as it's returning a new instance every time.

  1. Regarding the Interface Methods

The reason why you can't access encryptdata() method is that, because you are casting the created cipher object to super type(CipherStorage) and it doesn't have those methods. One of the options you can do is, move the 2 methods from your interface to CipherStorage and declare them (as well as the class itself) as abstract, and you won't need an interface in that case:

public abstract class CipherStorage {
    public abstract byte[] encryptData(String keyName, String input, @Nullable SharedPreferences pref);
    public abstract byte[] decryptData(String keyName, byte[] encrypted, @Nullable SharedPreferences pref);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Oke thanks for the answer. And what is the best option when CipherStorageRSA and CipherStorageAES get different methods?
if they have different public methods, then they are implementation specific, and you have to cast your cipher object to the concrete class when you need to call those specific methods. Depending on your situation, you might want to create a 2nd level abstraction underneath your base class. You can see how they defined the hierarchy of abstractions in Java collections.
1

Use the Factory Method pattern when

1.a class can't anticipate the class of objects it must create

2.a class wants its subclasses to specify the objects it creates

3.classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.