如何使用键建立一个Java工厂

我想构建一个命令解析器,它接收一个数据块并将该数据解析为特定命令的一个实例。这基本上是一个工厂,工厂返回的实例基于一个密钥。如何使用键建立一个Java工厂

所以更具体,说收到原始二进制数据块:

0×02 0×23 0×01 0×00 0×00 0x1F的

,以及该流的第三个字节定义的命令,我想创建的实例CommandOne。显然,根据命令将会有额外的方法来处理解析其余数据,但第一步是从命令编号中获取该命令的实例。我说这是一个使用密钥的工厂。

关于如何在java中建立工厂,有些非常直接,有些使用各种泛型和反射来讨论;但是我没有找到符合我想要实现的特定实现的运气。然而,我确实发现了与我正在努力完成的事情有关的点点滴滴,所以我将它们放在一个答案中,这是下面的第一个答案。这是一个很好的回应,还是我忽略了更简单的或更完整的东西?

回答:

以下是该解决方案的通用形式。这全部内置于包含所有命令和工厂的单个包中。请注意,添加新命令不需要对工厂本身进行任何更改。

这是所有命令必须实现的抽象类。它还包含工厂方法getInstance

public abstract class Commands 

{

private static Map<Integer,Constructor<?>> commandConstructorMap = null;

private static void loadMap()

{

commandConstructorMap = new HashMap<Integer,Constructor<?>>();

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

if(classLoader == null) return;

String myPathName = Commands.class.getName();

String myPath[] = myPathName.split("\\.");

if(myPath == null || myPath.length <= 1) return;

int pkgLen = myPath.length - 1;

StringBuilder pkgNm = new StringBuilder();

pkgNm.append(myPath[0]);

for(int i=1;i<pkgLen;i++)

pkgNm.append(".").append(myPath[i]);

String packageName = pkgNm.toString();

String path = packageName.replace('.', '/');

Enumeration<URL> resources;

try

{

resources = classLoader.getResources(path);

}

catch(IOException ioe)

{

return; // failure, just leave constructor empty

}

List<File> dirs = new ArrayList<File>();

while(resources.hasMoreElements())

dirs.add(new File(resources.nextElement().getFile()));

for(File dir:dirs)

{

if(!dir.exists() || !dir.isDirectory()) continue;

File[] files = dir.listFiles();

for(File file:files)

{

if(!file.isFile()) continue;

String fileName = file.getName();

if(!fileName.endsWith(".class")) continue;

try

{

String className = packageName+'.'+fileName.substring(0, fileName.length()-6);

Class<?> clazz = Class.forName(className);

Constructor<?> cons = clazz.getConstructor();

Object instance = cons.newInstance();

if(instance instanceof Commands)

{

commandConstructorMap.put(new Integer(((Commands) instance).getCommand()),cons);

}

}

catch(Exception e){} // do nothing special for exception, just don't add to map

}

}

}

public static Commands getInstance(Integer command) throws Exception

{

if(commandConstructorMap == null)

{

loadMap();

}

if(commandConstructorMap.containsKey(command))

return (Commands)commandConstructorMap.get(cmd).newInstance();

throw new Exception();

}

abstract Integer getCommand();

}

注抽象getCommand的返回类型是相同的用作密钥的类型,这是关系conrtol和几乎可以是任何所需的对象类型。这种机制的一个警告是,这确实会创建并最终丢弃每个命令对象的一个​​实例,但它只会执行一次,未来的调用将只创建由该密钥指示的类的单个实例。

这是一个命令文件实现的例子,显然需要其他代码来构建该命令的所有细节,这里的目标只是演示如何构建命令类的一部分这是在工厂中使用的。

public class CommandOne 

extends Commands

{

Integer getCommand()

{

return new Integer(1);

}

}

最后一个是如何工作的

public static void main(String[] args) 

{

try

{

Commands cmd = Commands.getInstance(new Integer(1));

if(cmd instanceof CommandOne)

System.out.println("Command using key 1 is: "+cmd.getClass().getSimpleName());

cmd = Commands.getInstance(new Integer(2));

if(cmd instanceof CommandTwo)

System.out.println("Command using key 2 is: "+cmd.getClass().getSimpleName());

cmd = Commands.getInstance(new Integer(3));

if(cmd instanceof CommandThree)

System.out.println("Command using key 3 is: "+cmd.getClass().getSimpleName());

}

catch(Exception e)

{

System.out.println("Command instantiation failed");

}

}

运行(假设有定义的命令CommandTwo和CommandThree以及所表现出的CommandOne)会是这样的结果证明:

命令使用密钥1是:CommandOne使用密钥2是

命令:使用密钥3 CommandTwo

命令是:CommandThree

以上是 如何使用键建立一个Java工厂 的全部内容, 来源链接: utcz.com/qa/261932.html

回到顶部