Java设计模式泛型化之工厂模式
来源:互联网 发布:时代网络投诉电话 编辑:程序博客网 时间:2024/05/17 04:27
关于工厂模式,本文就不详述了。大家可以百度。
基本的结构是这样的:
一个抽象产品(接口或者抽象类)几个具体的产品类去实现这个抽象产品一个工厂类一个调用类
下面是示例代码:
抽象产品(接口)
public interface Product {public void doSomething();}
具体产品实现类
public class ProductA implements Product {@Overridepublic void doSomething() {System.out.println("Product A do something.");}}
public class ProductB implements Product {@Overridepublic void doSomething() {System.out.println("Product B do something.");}}
产品工厂类
public class ProductFactory {public static void main(String[] args) {}public static Product createProduct(Class c) {Product prod = null;try {prod = (Product) Class.forName(c.getName()).newInstance();} catch (Exception e) {// TODO: handle exception}return prod;}}
工厂调用类
public class FactoryCaller {public static void main(String[] args) {Product prodA = ProductFactory.createProduct(ProductA.class);prodA.doSomething();Product prodB = ProductFactory.createProduct(ProductB.class);prodB.doSomething();}}
关于这个模式的泛型化,就在于产品工厂类里面的那个createProduct()方法了。我们都知道Class是一个raw-type,这种类型在使用的时候是要给出一个类型限定的。否则,会有一个警告。
Class is a raw type. References to generic type Class<T> should be parameterized
那么createProduct()方法要如何修改呢?
下面是一个简单的:
public class ProductFactory {public static void main(String[] args) {}public static Product createProduct(Class<? extends Product> c) {Product prod = null;try {prod = (Product) Class.forName(c.getName()).newInstance();} catch (Exception e) {// TODO: handle exception}return prod;}}
只有实现了Product接口的类,才可以传入。这样用没有问题。可是,还有另外一种创建方法。
在展示下一个示例之前,先把一个工具类抛出来,这是一个很有用的工具类。
import java.io.File;import java.io.IOException;import java.net.URL;import java.util.ArrayList;import java.util.Enumeration;import java.util.List;@SuppressWarnings("all")public class ClassUtils {public static List<Class> getAllClassesByInterface(Class c) {List<Class> returnClassList = new ArrayList<Class>();if (c.isInterface()) {String packageName = c.getPackage().getName();try {List<Class> allClasses = getClasses(packageName);for (int i = 0; i < allClasses.size(); i++) {if (c.isAssignableFrom(allClasses.get(i))) {if (!c.equals(allClasses.get(i))) {returnClassList.add(allClasses.get(i));}}}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}return returnClassList;}private static List<Class> getClasses(String packageName) throws ClassNotFoundException, IOException {ClassLoader cl = Thread.currentThread().getContextClassLoader();String path = packageName.replace('.', '/');Enumeration<URL> resources = cl.getResources(path);List<File> dirs = new ArrayList<File>();while (resources.hasMoreElements()) {URL resource = resources.nextElement();dirs.add(new File(resource.getFile()));}List<Class> classes = new ArrayList<Class>();for (File directory : dirs) {classes.addAll(findClasses(directory, packageName));}return classes;}private static List<Class> findClasses(File directory, String packageName) throws ClassNotFoundException {List<Class> classes = new ArrayList<Class>();if (!directory.exists()) {return classes;}File[] files = directory.listFiles();for (File file : files) {if (file.isDirectory()) {assert !file.getName().contains(".");classes.addAll(findClasses(file, packageName + "." + file.getName()));} else if (file.getName().endsWith(".class")) {classes.add(Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6)));}} // end forreturn classes;}}
它的作用是拿到某个接口下所有的实现类。
下面是改过后的ProductFactory类:
import java.util.List;import java.util.Random;public class ProductFactory {public static void main(String[] args) {}public static Product createProduct(Class<? extends Product> c) {Product prod = null;try {prod = (Product) Class.forName(c.getName()).newInstance();} catch (Exception e) {// TODO: handle exception}return prod;}public static Product createProduct() {Product prod = null;List<Class> concreteProductList = ClassUtils.getAllClassesByInterface(Product.class);Random r = new Random();int rand = r.nextInt(concreteProductList.size());prod = createProduct(concreteProductList.get(rand));return prod;}}
这里可能有人要问了,为啥List<Class>里面的那个Class不做泛型的类型限定?它不是raw-type类型吗?
这是因为ClassUtils的返回是Class是针对所有的类型的,如果这里的List<Class>做了类型限定,那么操作符两边的类型就不匹配了。
那么,如果把ClassUtils类里面的作类型限定呢?这个,你可以试试看。
你还可以这么改:
import java.util.List;import java.util.Random;@SuppressWarnings("all")public class ProductFactory<T extends Product> {public static <T extends Product> T createProduct(Class<T> c) {T t = null;try {t = (T) Class.forName(c.getName()).newInstance();} catch (Exception e) {// TODO: handle exception}return t;}public static Product createProduct() {Product prod = null;List<Class> concreteProductList = ClassUtils.getAllClassesByInterface(Product.class);Random r = new Random();int rand = r.nextInt(concreteProductList.size());prod = (Product) createProduct(concreteProductList.get(rand));return prod;}}
上面这段还是有点小问题的。你能找出来吗?
小改一下:
import java.util.List;import java.util.Random;@SuppressWarnings("all")public class ProductFactory<T extends Product> {public static <T> T createProduct(Class<T> c) {T t = null;try {t = (T) Class.forName(c.getName()).newInstance();} catch (Exception e) {// TODO: handle exception}return t;}public static Product createProduct() {Product prod = null;List<Class> concreteProductList = ClassUtils.getAllClassesByInterface(Product.class);Random r = new Random();int rand = r.nextInt(concreteProductList.size());prod = (Product) createProduct(concreteProductList.get(rand));return prod;}}
这里和上面的例子都用了泛型强转。我们在泛型十诫里面的第一条就是不要用泛型做强转。那么,为啥要在这里用呢?因为这里的强转赋值只有一次。如果多次,且类型不同的话会出问题。那么十诫第一条是不是不妥呢?也不是,它只是告诫你,要小心,小心,再小心。
再改进下,加一个“小仓库”:
import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Random;@SuppressWarnings("all")public class ProductFactory<T extends Product> {private static Map<String, Product> products = new HashMap<String, Product>();public static <T> T createProduct(Class<T> c) {T t = null;try {if (products.containsKey(c.getSimpleName())) {t = (T) products.get(c.getSimpleName());} else {t = (T) Class.forName(c.getName()).newInstance();}} catch (Exception e) {// TODO: handle exception}return t;}public static Product createProduct() {Product prod = null;List<Class> concreteProductList = ClassUtils.getAllClassesByInterface(Product.class);Random r = new Random();int rand = r.nextInt(concreteProductList.size());prod = (Product) createProduct(concreteProductList.get(rand));return prod;}}
如果已经创建了,直接拿出来用就可以了。
1 0
- Java设计模式泛型化之工厂模式
- Java设计模式之工厂设计模式
- [java]设计模式之工厂设计模式
- Java设计模式之工厂设计模式
- Java设计模式之工厂设计模式
- JAVA设计模式之工厂设计模式
- java设计模式之工厂设计模式
- Java设计模式之工厂设计模式
- 《java设计模式》之工厂设计模式
- JAVA设计模式之工厂模式之简单工厂模式
- JAVA设计模式之工厂模式之工厂方法模式
- JAVA设计模式之工厂模式之抽象工厂模式
- Java设计模式之工厂
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式+抽象工厂模式)
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式+抽象工厂模式)
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式+抽象工厂模式)
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式+抽象工厂模式)
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式+抽象工厂模式)
- TextView drawaLeft 居中
- Windows平台下eclipse 配置android NDK 开发环境
- 世界时间与本地时间的转化
- 网络游戏服务器端架构设计
- Tapestry3 学习笔记(一) 配置文件介绍
- Java设计模式泛型化之工厂模式
- 项目中一些js小的技巧总结
- Oracle11g在Windows操作系统下的安装
- William Nelson Joy
- centos tomcat下安装多个solr应用
- maven核心思想“约定大于配置”
- 设计模式(4) 原型模式(Prototype)
- Astronomers Discover Secrets About Ancient Supernovae
- 面试常见问题及解答,部分来源于网络