- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
考虑一个场景,我想要获取 String data
一些数据并将其解析为某种类型的对象,例如 Animal
。 免责声明:虽然很长,但这只是一个sscce;我的实际项目与猫的声音没什么关系:)
要求:
C
可能指abstract class Cat
,和D
可能指abstract class Dog
.CS
可能是ThaiCat extends Cat
有参数"Siamese"
和CK
可能是ThaiCat extends Cat
有参数"Korat"
,和CB
可能是AmericaCat extends Cat
有参数Bengal
data
String
里面还有其他信息。例如,它可能有动物的名称。不用担心如何解析这些数据,这段代码将在abstract class
之间共享。 (它可以解析所有 Cat
子类型都正确的内容,并且子类将解析出其余所需的数据)。第一个解决方案,从这里开始:
public enum AnimalType {
CAT ('C') { Animal makeAnimal(String data) { return CatType.makeCat(data); },
DOG ('D') { Animal makeAnimal(String data) { return DogType.makeDog(data); };
private char type;
public char getType() { return type; }
private AnimalType(char type) { this.type = type; }
abstract Animal makeAnimal(String data);
private static Map<Character, AnimalType> animalMap = new HashMap<>();
static {
for(AnimalType currentType : AnimalType.values()) {
animalMap.put(currentType.getType(), currentType());
}
}
public static Animal makeAnimal(String data) {
return animalMap.get(data.charAt(0)).makeAnimal(data);
}
}
public enum CatType {
BENGAL ('B') { Cat makeCat(String data) { return new AmericaCat(data, this) },
RAGDOLL ('R') { Cat makeCat(String data) { return new AmericaCat(data, this) },
KORAT ('K') { Cat makeCat(String data) { return new ThaiCat(data, this) },
SIAMESE ('S') { Cat makeCat(String data) { return new ThaiCat(data, this) };
private char type;
public char getType() { return type; }
private CatType(char type) { this.type = type; }
abstract Cat makeCat(String data, CatType type);
private static Map<Character, CatType> catMap = new HashMap<>();
static {
for(CatType currentType : CatType.values()) {
catMap.put(currentType.getType(), currentType());
}
}
static Cat makeCat(String data) {
return catMap.get(data.charAt(1)).makeCat(data);
}
}
这一切都很好,它应该快速、干净、正确的代码委托(delegate)等等。现在,如果动物突然产生依赖性怎么办(我正在使用 Guice)?假设我有一个包含动物声音的图书馆,我希望能够执行 animal.speak()
调用声音对象的功能被封装在 Animal
中。 .
以下是我考虑过的一些事情:
MapBinder
设置Enum
-> Cat
子类配对。然后绑定(bind)Map<K, Provider<V>>
映射到工厂类,并传递data
进入Cat
对象作为创建后的方法调用makeCat
方法调用工厂中正确的方法。问题是,我无法将工厂注入(inject)到枚举实例中,Guice 建议不要使用静态注入(inject)。因此,我必须沿着方法链一路传递我的工厂,这似乎违背了目的。而且,这并不能解决不允许错误的字符串调用错误的构造函数的问题。最好的解决方案是什么?
最佳答案
你真的有两个问题:
Guice 真的非常想要在启动时使用启动时提供的信息制作一个大的对象图。然而,它的强大之处在于它能够根据运行时的条件改变其行为 - 因此许多基于 Guice 构建的框架都做了一些事情来实现这一点 - Servlet 支持有其请求范围 em> 它允许注入(inject) servlet 请求,等等。
可以通过三种基本方法将动态创建的对象提供给 Guice 在创建对象时使用:
Provider<Animal>
它以某种方式获取相关数据(通常使用 ThreadLocal
- 自定义范围通常是此模式的概括)并创建正确的对象假设输入是在运行时动态提供的,并且假设您有一个工厂或提供者将创建正确的对象,您需要说服 Guice 将该对象提供给您的代码,或者您需要为获取数据的信息创建一些替代路径。
通常的方法是使用 ThreadLocal
- 即在进行可能触发 Animal
实例化的调用之前您可以设置 ThreadLocal
包含要解析的字符串;如果某些东西确实需要,您的解析代码将被调用。如果您发现使用了ThreadLocal
令人厌恶的是,您可以实现 Scope (或使用一个可以实现 Scope 的库,如上面链接的库) - 但通常它只是使用 ThreadLocal
在幕后。
以下是所有这些内容的简化示例:
public class App {
public interface Animal {
}
private static class Cat implements Animal {
}
public static void main(String[] args) {
ThreadLocal<String> theData = new ThreadLocal<>();
MyModule module = new MyModule(theData);
Injector inj = Guice.createInjector(module);
// Try a test run
theData.set("Cat thing");
try {
Animal animal = inj.getInstance(Animal.class);
assert animal instanceof Cat;
System.out.println("Got " + animal);
} finally {
theData.remove();
}
}
private static class MyModule extends AbstractModule {
private final ThreadLocal<String> data;
public MyModule(ThreadLocal<String> data) {
this.data = data;
}
@Override
protected void configure() {
bind(new TypeLiteral<ThreadLocal<String>>() {
}).toInstance(data);
bind(Animal.class).toProvider(AnimalProvider.class);
}
}
private static class AnimalProvider implements Provider<Animal> {
private final ThreadLocal<String> data;
@Inject
public AnimalProvider(ThreadLocal<String> data) {
this.data = data;
}
public Animal get() {
String providedAtRuntime = data.get();
assert providedAtRuntime != null;
switch (providedAtRuntime.charAt(0)) {
case 'C':
return new Cat();
// ...
default:
throw new IllegalArgumentException(providedAtRuntime);
}
}
}
}
最后要考虑的是如何创建 Animal 实例。如果动物的数量很小且有限,并且 Animal 对象是无状态的,您可能只需迭代所有可能的组合并在启动时创建所有它们,然后您只需进行简单的查找。或者您可以解析输入并即时做出决定 - 取决于您的需要。
我建议不要对这些东西使用枚举 - 你迟早会发现你想要实现 Animal
其中包装另一个 Animal
并委托(delegate)给它或类似的东西,并且您无法即时创建枚举实例。
您可以做的是拥有一个 Animal 接口(interface),然后是一个实现该接口(interface)的枚举 - 这样您就可以获得接口(interface)的灵 active ,并且可以在常见情况下使用枚举 - 只需编写所有代码都指向接口(interface),而不是枚举。
如果您确实需要限制某些代码仅采用 Animal 的枚举实例,则无需将该代码绑定(bind)到特定枚举即可做到这一点:
public <A extends Animal & Enum<A>> void foo(A animal) { ... }
这为您提供了枚举的所有好处,同时仍然编写可以在将来在新枚举上重用的代码。
关于java - 使用 Guice、枚举和静态工厂方法设计工厂框架,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17710053/
我应该执行以下操作: 可能通过服务/工厂,使用 $q(异步)查询 API 以获取大型名称数据集 有另一个服务(也是异步的),它应该只返回上述工厂的元素,如果它们与某个字符串(搜索字段)匹配。目的是缩小
我有一个通用的基类。我有一个实现基类的具体类。 我将如何创建工厂类/方法来交付不同类型的具体类? 举个例子: public class ReceiverBase where T : IInte
我正在查看以下链接中的 Ninject Factory 扩展: http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-intro
工厂、提供商和服务这三个术语之间有什么区别? 刚刚了解 NHibernate 及其存储库模式(POCO 类等)。 最佳答案 工厂:通过将一堆位组合在一起或基于某种上下文选择类型来组装类 Provide
使用CGLIB我可以做到 final var enhancer = new Enhancer(); enhancer.setUseCache(false); enhancer.setSuperclas
我试图在 Kotlin 中使用伴随对象工厂方法(相当于 Java 中的静态工厂方法)创建一个嵌套内部类。这是我的代码的简化版本。 class OuterClass { var myData:L
我正在为我的大学做一个项目,但遇到了问题。 基本上,该项目由一个客户端-服务器应用程序组成,我想创建一个用于通信的 Packet 类。数据包由 header 和主体组成。现在问题来了。我可以有一些不同
这个问题在这里已经有了答案: Why doesn't polymorphism work without pointers/references? (6 个答案) What is object sl
我正在制作一个套接字工厂。我希望每个外部应用程序都使用 Socket 类的接口(interface),它是几个类(ServerSocketTCP、ClientSocketTCP、ServerSocke
我是 angularjs 的新手,我正在尝试创建一个小型电影数据库。这是我第一次使用工厂,我想确保这是正确的方法,以及如何在另一个功能中使用这个工厂,如下所示? 我希望这个工厂只运行一次,这样我就可以
这个问题在这里已经有了答案: Java inner class and static nested class (28 个答案) 关闭 5 年前。 public class DataFactory
我看过很多关于 C++ 工厂的帖子,但到目前为止我还没有看到解决我的问题的解决方案。 (虽然我可能遗漏了一些东西。) 示例控制台应用程序: #include #include #include
这是一个简单的 C++ 项目,有 2 种设计模式:单例和工厂,sigleton 也是一个模板化类,一个接口(interface) (IHash) 和一个类 (Hash1)。一个简单的工厂类 (Hash
这个问题类似于Factory and generics ,并且可能有相同的答案,但它是不同的。我有一个通用基类,它将由完全独立的 JAR 中的类进行扩展。所述 JAR 应该能够在不更改任何其他代码的情
问题是我需要为传递的类创建一个新实例 有没有办法重写这个函数,让它可以接受任意数量的参数? function createInstance(ofClass, arg1, arg2, arg3, ...
我想用简单的 C++ 语法创建一个简单的工厂方法: void *createObject(const char *str,...) { if(!strcmp("X",str)) retu
经过大约 10 个月的程序化 PHP 学习后,我现在正尝试着手研究基本的 OOP 原则和设计模式。这是一个爱好,我没有那么多时间去追求它,所以请原谅这个问题的水平很低。 我的网站(目前 100% 程序
我有一个简单的问题。 我如何编写一个工厂来定义使用 make() 或 create() 的关系,具体取决于原始调用 make() 还是 create()? 这是我的用例: 我有一个简单的工厂 /**
我正在尝试在延迟加载模块中提供 APP_BASE_HREF 注入(inject) token ,然而,工厂方法根本没有被调用。 在这里https://github.com/MaurizioCascia
我有以下 ast: import { factory as f } from 'typescript' const typeDeclaration = f.createTypeAliasDeclara
我是一名优秀的程序员,十分优秀!