构建类

时间:2010-11-03 20:19:54

标签: java oop idiomatic

我应该编写代码来模拟三种加密技术的工作: - Caesar CipherColumnar TranspositionRSA。我创建了一个名为Encryption的接口

public interface Encryption {
    public String encrypt(String key, String message);
}

并制作了两个班级。 CaesarCipherEncryptor和

public class CaeserCipherEncryptor implements Encryption {
    private static final CaeserCipherEncryptor INSTANCE = new CaeserCipherEncryptor();

    private CaeserCipherEncryptor(){ }

    public static CaeserCipherEncryptor getInstance(){
        return INSTANCE;
    }

    public String encrypt(String key, String message) {
        int noOfShifts = Integer.parseInt(key);
        String cipherText = "";
        for(char c:message.toCharArray()){
            //to handle UpperCase and LowerCase alphabets
            if((Character.isUpperCase(c) && ((c+noOfShifts) > 90)) || (Character.isLowerCase(c) && ((c+noOfShifts) > 122)))
                c = (char)((c + noOfShifts) - 26);
            else 
                c = (char)(c + noOfShifts);
            cipherText += c;
        }
        return cipherText;
    }
}

ColumnarTranspositionEncryptor实现它。

import java.util.ArrayList;
public class ColumnarTranspositionEncryptor implements Encryption {
    private static final ColumnarTranspositionEncryptor INSTANCE = new ColumnarTranspositionEncryptor();

    public static ColumnarTranspositionEncryptor getInstance(){
        return INSTANCE;
    }

    private ColumnarTranspositionEncryptor(){}


    @Override
    public String encrypt(String key, String message) {
        int rowLength = key.length();
        key.toUpperCase();
        ArrayList<Integer> finalOrder = new ArrayList<Integer>();
        for(int i=0;i<rowLength;i++){
            int rank=0;
            char c = key.charAt(i);
            for(int j=0;j<rowLength;j++){
                if(c>key.charAt(j))
                    rank++;
            }
            finalOrder.add((rank+1));
        }
        ArrayList<String> rowsOfString=new ArrayList<String>();
        for(;message.length()>rowLength;message=message.substring(rowLength)){
            rowsOfString.add(message.substring(0, rowLength));
        }
        for(;message.length()>0 && message.length()<rowLength;){
            char c=65;
            message += (char)(c+new java.util.Random().nextInt(26));
        }
        rowsOfString.add(message);
        String cipherText = "";
        for(int i=1;i<=finalOrder.size();i++){
            int j=finalOrder.indexOf(i);
            for(String s:rowsOfString){
                cipherText += s.charAt(j);
            }
        }
        System.out.println("Alphabetical order and columns:");
        for(int i:finalOrder)
            System.out.print(i + " ");
        System.out.println();
        System.out.println();
        for(String s:rowsOfString){
            for(int i=0;i<s.length();i++)
                System.out.print(s.charAt(i) + " ");
            System.out.println();
        }
        // TODO Auto-generated method stub
        return cipherText;
    }
}

这两个类是Singeltons,因为它们是简单的算法。但是,正如维基百科链接中给出的,在RSA加密中,我需要将特定用户的状态存储在实体n,phiOfN,publicKey和privateKey中,以便模拟加密过程。请建议一个更通用的解决方案来构建RSAEncryptor类。下面给出的代码是我能解决的所有问题:|。

import java.util.ArrayList;
import java.math.BigInteger;

public class RSAUser {
    private int p,q,n,phiOfN, publicExponent, privateExponent;

    private static int gcd(int a, int b) {
        if (b == 0)
            return a;
        else
            return gcd(b, a % b);
    }
    public RSAUser(int p,int q){
        this.p = p;
        this.q = q;
        n = p * q;
        int phiOfN = (p - 1) * (q - 1);
        int min = Math.min(p, q);
        this.publicExponent = 2;
        ArrayList<Integer> x = new ArrayList<Integer>();
        for (; publicExponent < min - 1; publicExponent++) {
            if (RSAUser.gcd(publicExponent, phiOfN) == 1)
                x.add(publicExponent);
        }
        this.publicExponent = x.get(new java.util.Random().nextInt(x.size()));
        privateExponent = phiOfN / publicExponent;
        for (int i = 1;; i++) {
            long product = phiOfN * i + 1;
            if (product % publicExponent == 0) {
                privateExponent = (int)product / publicExponent;
                break;
            }
        }
        System.out.println("Public Key:"+this.getPublicKey()+"\nPrivate Key:"+this.getPrivateKey());
    }
    //to print in the format "(n, publicExponent)"
    public String getPublicKey(){
        return "("+Integer.toString(n)+","+Integer.toString(publicExponent)+")";
    }

    public String getPrivateKey(){
        return "("+Integer.toString(n)+","+Integer.toString(privateExponent)+")";
    }
}

public class RSAEncryptor implements Encryption {
    private static RSAEncryptor instance = new RSAEncryptor();

    private RSAEncryptor(){
    }

    public static RSAEncryptor getInstance(){
        return instance;
    }
    @Override
    public String encrypt(String key, String message) {
        key.trim();
        String[] keys = key.split(",");
        String n = keys[0].substring(1).trim();
        String publicExponent = keys[1].trim();
        publicExponent = publicExponent.substring(0, publicExponent.length()-1);
        BigInteger m = new BigInteger(message);
        return m.pow(Integer.parseInt(publicExponent)).mod(new BigInteger(n)).toString(10);
    }

}

这种类的结构是否正确?这是适当的OO设计吗?谢谢,提前。

1 个答案:

答案 0 :(得分:5)

一个简单的解决方案是不使用你所称的单身人士。每次要加密时,只需创建一个加密实现的新实例。如果执行此操作,则可以在加密实例上存储所需的所有状态。这些实例只能用一次;你可以防止他们在代码中重复使用。

或者,由于您需要存储状态,因此可以创建EncryptionContext类,其实例将传递给您的encrypt方法。所有必要的状态都可以存储在这些上下文实例中,您可以对上下文进行错误检查,以确保在任何给定步骤中您需要执行的所有信息都存在。如果你做了这样的事情,你可以重用你的加密实现实例。你必须改变你的界面..

关于您对OO设计的担忧,您似乎正处于正确的轨道上。随着时间的推移获得适当的OO技能,你无法在课堂上学到它们。您正在正确使用接口,您正在询问有关如何处理状态的正确问题。您可以轻松地将解决方案集成到Strategy Pattern中,这很好。

编辑---

如果一个实现需要状态,那么它们也可能都需要状态。除非您想采用第三种选择,即为有状态加密算法创建单独的接口。但是,这是没有吸引力的,因为这是一个实现细节,不需要反映在接口中,其目的是表示行为而不是实现。我仍然会选择上面两个选项中的一个,或者是好的并且是OO,恕我直言。