我为我生成了一系列课程因此我无法修改这些类以添加多态行为。不幸的是,我需要根据其继承中的类型有一些不同的行为。
一种解决方案是为所有这些对象编写装饰器,这样我就可以使用类似DDD的行为来扩充这些对象,或者使用一些访问者模式。但是,我想到了另一种更简单的方法来根据类型执行一些不同的行为。
以下是我的想法,本身就是一个有趣的练习,探讨了Lambda在Java中的可能性:
Map<Class, SomeLambdaFunction<String>> typeMap = ImmutableMap.<Class, SomeLambdaFunction<String>>builder()
.put(SubClassA.class, () -> someCondition() ? "valueA" : "valueB")
.put(SubClassB.class, () -> aStringMethod() + anotherStringMethod())
.build();
我想查找&#39;这样一种行为。由于我不希望这些生成的课程集合再次发生变化(这是旧的遗留内容),我并不担心违反Open / Closed Principle。
这可能吗?
答案 0 :(得分:2)
Lambda
你是什么意思? Class
不是Java语言中的类型,也不是Java标准库中定义的类型。在运行时没有“lambda”这样的东西。至少,如果你没有定义它,就没有这样的事情。
lambda 表达式只是一种创建新对象的方法。当然,您不能使用它来创建任何对象,但您可以使用它来创建属于实现某些特定功能接口的匿名类的对象。但是,lambda的结果与所有其他类型的对象并没有本质的区别。它只是 一个对象。
所以,你真正要问的是,“是否有可能创建一个将Map<Class, Foobar>
类型的键映射到某些其他类型的值的地图?”
是。这是可能的。
更具体地说,您要求的是Foobar
,其中SomeLambdaFunction<String>
是您的lambda所有实现的功能接口类型的名称。
我认为如果你这样编写它会更有意义,而不是写@FunctionalInterface
interface CustomBehavior {
String doCustomThing();
}
Map<Class, CustomBehavior> typeMap =
ImmutableMap.<Class, CustomBehavior>builder()
.put(SubClassA.class, () -> someCondition() ? "valueA" : "valueB")
.put(SubClassB.class, () -> aStringMethod() + anotherStringMethod())
.build();
:
String
那些lambda表达式不返回CustomBehavior
个对象;他们返回@FunctionalInterface
interface CustomBehavior {
String doCustomThing();
}
class CustomBehaviorA implements CustomBehavior {
public String doCustomThing() {
return someCondition() ? "valueA" : "valueB";
}
}
class CustomBehaviorB implements CustomBehavior {
public String doCustomThing() {
return aStringMethod() + anotherStringMethod();
}
}
Map<Class, CustomBehavior> typeMap =
ImmutableMap.<Class, CustomBehavior>builder()
.put(SubClassA.class, new CustomBehaviorA())
.put(SubClassB.class, new CustomBehaviorB())
.build();
个对象。下面的代码与上面的代码完全相同,除了它使用命名的classess而不是匿名类。
List<User> userList = new List<User>()
{
new User {IdUser = 1, Login = "Frank" },
new User {IdUser = 2, Login = "Pat" },
new User {IdUser = 3, Login = "Max" },
new User {IdUser = 4, Login = "Paul" },
new User {IdUser = 5, Login = "John" }
};
User newUser = new User()
{
IdUser = 3,
Login = "Chris"
};
var foundUser = userList.FirstOrDefault(item => item.IdUser == newUser.IdUser);
if(foundUser != null)
userList.Remove(foundUser)
userList.Add(newUser);
答案 1 :(得分:-1)
这是可能的,但您必须使用接口作为值类型,然后使用lambda定义实现该接口。
一些常见的界面是Runnable,Callable和Supplier或Function。 Runnable 没有返回值而 Callable 抛出Exception
强制您抓住它, Function 需要一个参数。 供应商仍然是一个很好的候选人。
以下是基于供应商和子类的密钥的示例:
public String getLambdaValueForKey(String key) {
final Map<Class<? extends YourBaseClass>, Supplier<String>> lambdaMap = ImmutableMap.<Class<? extends YourBaseClass>, Supplier<String>>builder()
.put(SubclassA.class, () -> someCondition() ? "valueA" : "valueB")
.put(SubclassB.class, () -> aStringMethod() + anotherStringMethod())
.build();
return lambdaMap.get(key).get(); // the 2nd get is Supplier's .get()
}
但是,正如评论中提到的那样,一般情况下,您可以通过明确的instanceof
检查获得更好的效果。只有在非常具体的情况下(如固定生成的课程因遗留问题而无法改变),这将在长期内发挥作用。