hca*_*ver 23 java generics observer-pattern
的java.util.Observer和java.util.Observable丑陋的.它们需要使类型安全风扇不舒服的类型的演员表,并且你不能将一个类定义Observer为多个事物而没有丑陋的演员阵容.事实上,在" 我如何知道Observer类在Java中发送的通用对象? "中,应答者说每个观察者/可观察者中只应使用一种类型的数据.
我正在尝试在Java中创建一个通用版本的观察者模式来解决这两个问题.它与之前提到的帖子没有什么不同,但这个问题没有明显解决(最后一个评论是来自OP的未回答的问题).
hca*_*ver 14
Observer.java
package util;
public interface Observer<ObservedType> {
public void update(Observable<ObservedType> object, ObservedType data);
}
Run Code Online (Sandbox Code Playgroud)
Observable.java
package util;
import java.util.LinkedList;
import java.util.List;
public class Observable<ObservedType> {
private List<Observer<ObservedType>> _observers =
new LinkedList<Observer<ObservedType>>();
public void addObserver(Observer<ObservedType> obs) {
if (obs == null) {
throw new IllegalArgumentException("Tried
to add a null observer");
}
if (_observers.contains(obs)) {
return;
}
_observers.add(obs);
}
public void notifyObservers(ObservedType data) {
for (Observer<ObservedType> obs : _observers) {
obs.update(this, data);
}
}
}
Run Code Online (Sandbox Code Playgroud)
希望这对某人有用.
Pet*_*rey 11
我更喜欢使用注释,因此侦听器可以侦听不同类型的事件.
public class BrokerTestMain {
public static void main(String... args) {
Broker broker = new Broker();
broker.add(new Component());
broker.publish("Hello");
broker.publish(new Date());
broker.publish(3.1415);
}
}
class Component {
@Subscription
public void onString(String s) {
System.out.println("String - " + s);
}
@Subscription
public void onDate(Date d) {
System.out.println("Date - " + d);
}
@Subscription
public void onDouble(Double d) {
System.out.println("Double - " + d);
}
}
Run Code Online (Sandbox Code Playgroud)
版画
String - Hello
Date - Tue Nov 13 15:01:09 GMT 2012
Double - 3.1415
Run Code Online (Sandbox Code Playgroud)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subscription {
}
public class Broker {
private final Map<Class, List<SubscriberInfo>> map = new LinkedHashMap<Class, List<SubscriberInfo>>();
public void add(Object o) {
for (Method method : o.getClass().getMethods()) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (method.getAnnotation(Subscription.class) == null || parameterTypes.length != 1) continue;
Class subscribeTo = parameterTypes[0];
List<SubscriberInfo> subscriberInfos = map.get(subscribeTo);
if (subscriberInfos == null)
map.put(subscribeTo, subscriberInfos = new ArrayList<SubscriberInfo>());
subscriberInfos.add(new SubscriberInfo(method, o));
}
}
public void remove(Object o) {
for (List<SubscriberInfo> subscriberInfos : map.values()) {
for (int i = subscriberInfos.size() - 1; i >= 0; i--)
if (subscriberInfos.get(i).object == o)
subscriberInfos.remove(i);
}
}
public int publish(Object o) {
List<SubscriberInfo> subscriberInfos = map.get(o.getClass());
if (subscriberInfos == null) return 0;
int count = 0;
for (SubscriberInfo subscriberInfo : subscriberInfos) {
subscriberInfo.invoke(o);
count++;
}
return count;
}
static class SubscriberInfo {
final Method method;
final Object object;
SubscriberInfo(Method method, Object object) {
this.method = method;
this.object = object;
}
void invoke(Object o) {
try {
method.invoke(object, o);
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
一个现代的更新: ReactiveX是一个非常好的基于Observer模式的异步编程API,它是完全通用的.如果您使用Observer/Observable将数据或事件从代码中的一个位置"流"到另一个位置,那么您一定要查看它.
它基于函数式编程,因此使用Java 8的lambda语法看起来非常流畅:
Observable.from(Arrays.asList(1, 2, 3, 4, 5))
.reduce((x, y) -> x + y)
.map((v) -> "DecoratedValue: " + v)
.subscribe(System.out::println);
Run Code Online (Sandbox Code Playgroud)