我应该如何根据用户选择来选择实例化哪个具体实现?

我应该如何根据用户选择来选择实例化哪个具体实现?,第1张

我应该如何根据用户选择来选择实例化哪个具体实现?

tl; dr 我建议使用抽象工厂模式。

长答案:

为了比较这些方法,我在下面附加了四个可能的解决方案。总结如下:

  1. 使用抽象工厂模式
  2. 使用一个由用户直接选择的String来通过名称实例化一个类
  3. 接受用户直接选择的字符串,并将其转换为另一个字符串,以按名称实例化类
  4. 接受用户直接选择的String并将其转换为Class对象以实例化该类
比较方式使用
Class::forName

首先,反射解决方案2和3用提供类名称的String标识类对象。这样做很不好,因为它破坏了自动重构工具:重命名类时,不会更改String。而且,不会有编译器错误。该错误将仅在运行时可见。

请注意,这不依赖于重构工具的质量:在解决方案2中,提供类名称的String可能会以您认为最模糊的方式构造。它甚至可以由用户输入或从文件中读取。重构工具无法完全解决此问题。

解决方案1和4没有这些问题,因为它们直接链接到类。

GUI与类名称的耦合

由于解决方案2直接使用用户提供的String进行反射以按名称标识类,因此​​GUI耦合到了您在代码中使用的类名称。这很不好,因为这要求您在重命名类时更改GUI。重命名类应始终尽可能地容易,以实现轻松的重构。

解决方案1、3和4不存在此问题,因为它们将GUI使用的String转换为其他字符串。

流量控制的例外

使用反射方法

forName
和时,解决方案2、3和4必须处理异常
newInstance
。解决方案2甚至必须使用异常进行流控制,因为它没有其他任何方法来检查输入是否有效。使用异常进行流控制通常被认为是不好的做法。

解决方案1不存在此问题,因为它不使用反射。

反思的安全性问题

解决方案2直接使用用户提供的String进行反射。这可能是一个安全问题。

解决方案1、3和4不存在此问题,因为它们将用户提供的String转换为其他内容。

特殊装载机的反射

您不能在所有环境中轻松使用这种类型的反射。例如,使用OSGi时您可能会遇到问题。

解决方案1不存在此问题,因为它不使用反射。

带参数的构造函数

给定的示例仍然很简单,因为它不使用构造函数参数。在构造函数参数上使用相似的模式是很常见的。在这种情况下,解决方案2、3和4很难看,请参阅我可以将Class.newInstance()与构造函数参数一起使用吗?

解决方案1只需将更

Supplier
改为与构造函数签名匹配的功能接口。

使用工厂(方法)创建复杂的水果

解决方案2、3和4要求您通过构造函数实例化水果。但是,这可能是不可取的,因为您通常不想将复杂的初始化逻辑放入构造函数中,而是放入工厂(方法)中。

解决方案1不存在此问题,因为它允许您将任何可创建水果的函数放入地图中。

代码复杂度

以下是介绍代码复杂性的元素以及出现的解决方案:

  • 在1、3和4中创建地图
  • 2、3和4中的异常处理

上面已经讨论了异常处理。

映射是代码的一部分,它将用户提供的String转换为其他内容。因此,该地图解决了上述许多问题,这意味着它可以达到目的。

请注意,映射也可以由

List
或数组替换。但是,这不会改变上述任何结论。

码通用密码
public interface Fruit {    public static void printOptional(Optional<Fruit> optionalFruit) {        if (optionalFruit.isPresent()) { String color = optionalFruit.get().getColor(); System.out.println("The fruit is " + color + ".");        } else { System.out.println("unknown fruit");        }    }    String getColor();}public class Apple implements Fruit {    @Override    public String getColor() {        return "red";    }}public class Banana implements Fruit {    @Override    public String getColor() {        return "yellow";    }}
抽象工厂(1)
public class AbstractFactory {    public static void main(String[] args) {        // this needs to be executed only once        Map<String, Supplier<Fruit>> map = createMap();        // prints "The fruit is red."        Fruit.printOptional(create(map, "apple"));        // prints "The fruit is yellow."        Fruit.printOptional(create(map, "banana"));    }    private static Map<String, Supplier<Fruit>> createMap() {        Map<String, Supplier<Fruit>> result = new HashMap<>();        result.put("apple", Apple::new);        result.put("banana", Banana::new);        return result;    }    private static Optional<Fruit> create( Map<String, Supplier<Fruit>> map, String userChoice) {        return Optional.ofNullable(map.get(userChoice)) .map(Supplier::get);    }}
倒影(2)
public class Reflection {    public static void main(String[] args) {        // prints "The fruit is red."        Fruit.printOptional(create("stackoverflow.fruit.Apple"));        // prints "The fruit is yellow."        Fruit.printOptional(create("stackoverflow.fruit.Banana"));    }    private static Optional<Fruit> create(String userChoice) {        try { return Optional.of((Fruit) Class.forName(userChoice).newInstance());        } catch (InstantiationException    | IllegalAccessException    | ClassNotFoundException e) { return Optional.empty();        }    }}
地图反射(3)
public class ReflectionWithMap {    public static void main(String[] args) {        // this needs to be executed only once        Map<String, String> map = createMap();        // prints "The fruit is red."        Fruit.printOptional(create(map, "apple"));        // prints "The fruit is yellow."        Fruit.printOptional(create(map, "banana"));    }    private static Map<String, String> createMap() {        Map<String, String> result = new HashMap<>();        result.put("apple", "stackoverflow.fruit.Apple");        result.put("banana", "stackoverflow.fruit.Banana");        return result;    }    private static Optional<Fruit> create( Map<String, String> map, String userChoice) {        return Optional.ofNullable(map.get(userChoice)) .flatMap(ReflectionWithMap::instantiate);    }    private static Optional<Fruit> instantiate(String userChoice) {        try { return Optional.of((Fruit) Class.forName(userChoice).newInstance());        } catch (InstantiationException    | IllegalAccessException    | ClassNotFoundException e) { return Optional.empty();        }    }}
类图反射(4)
public class ReflectionWithClassMap {    public static void main(String[] args) {        // this needs to be executed only once        Map<String, Class<? extends Fruit>> map = createMap();        // prints "The fruit is red."        Fruit.printOptional(create(map, "apple"));        // prints "The fruit is yellow."        Fruit.printOptional(create(map, "banana"));    }    private static Map<String, Class<? extends Fruit>> createMap() {        Map<String, Class<? extends Fruit>> result = new HashMap<>();        result.put("apple", Apple.class);        result.put("banana", Banana.class);        return result;    }    private static Optional<Fruit> create( Map<String, Class<? extends Fruit>> map, String userChoice) {        return Optional.ofNullable(map.get(userChoice)) .flatMap(ReflectionWithClassMap::instantiate);    }    private static Optional<Fruit> instantiate(Class<? extends Fruit> c) {        try { return Optional.of(c.newInstance());        } catch (InstantiationException    | IllegalAccessException e) { return Optional.empty();        }    }}


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5490735.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-12
下一篇2022-12-12

发表评论

登录后才能评论

评论列表(0条)

    保存