I have created a class in Typescript that implements a simple stream (FRP). Now I want to extend it with client side functionality (streams of events). To illustrate my problem, here is some pseudo-code:
class Stream<T> {
map<U>(f: (value: T) => U): Stream<U> {
// Creates a new Stream instance that maps the values.
}
// Quite a few other functions that return new instances.
}
This class can be used both on the server and on the client. For the client side, I created a class that extends this one:
class ClientStream<T> extends Stream<T> {
watch(events: string, selector: string): Stream<Event> {
// Creates a new ClientStream instance
}
}
Now the ClientStream class knows about map but the Stream class doesn't know about watch. To circumvent this, functions call a factory method.
protected create<U>(.....): Stream<U> {
return new Stream<U>(.....)
}
The ClientStream class overrides this function to return ClientStream instances. However, the compiler complains that ClientStream.map returns a Stream, not a ClientStream. That can be 'solved' using a cast, but besides being ugly it prevents chaining.
I don't really like this pattern, but I have no other solution that is more elegant. Things I've thought about:
- Use composition (decorator). Not really an option given the number of methods I would have to proxy through. And I want to be able to add methods to
Streamlater without having to worry aboutClientStream. - Mix
StreamintoClientStream. More or less the same problem,ClientStreamhas to know the signatures of the functions that are going to be mixed in (or not? Please tell). - Merge these classes into one. This is a last resort, the
watchfunction has no business being on the server.
Do you have a better (more elegant) solution? If you have an idea that gets closer to a more functional style, I'd be happy to hear about it. Thanks!
Aucun commentaire:
Enregistrer un commentaire