Skip to content

Instantly share code, notes, and snippets.

@will-molloy
Last active June 28, 2019 11:09
Show Gist options
  • Save will-molloy/53138688693a28f806c99c36ebe82d12 to your computer and use it in GitHub Desktop.
Save will-molloy/53138688693a28f806c99c36ebe82d12 to your computer and use it in GitHub Desktop.
Java sealed class (abstract enum)
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
/**
* Example 1. __Unsealed
*
* <p>Can implement the root abstraction, but we want to restrict the subtypes to provide rigidity
* and exhaustiveness of the type.
*/
public abstract class __Unsealed<T> implements Supplier<T> {
abstract String getName();
public abstract static class Multiple extends __Unsealed<Stream<Integer>> {}
public abstract static class Single extends __Unsealed<Optional<Integer>> {
public final Multiple asMultiple() {
return new Multiple() {
@Override
public Stream<Integer> get() {
return Single.this.get().map(Stream::of).orElse(Stream.empty());
}
@Override
public String getName() {
return Single.this.getName();
}
};
}
}
}
public class MultipleInstance extends __Unsealed.Multiple {
@Override
public String getName() {
return "I have 0 or more integer";
}
@Override
public Stream<Integer> get() {
return Stream.of(1);
}
}
public class SingleInstance extends __Unsealed.Single {
@Override
public String getName() {
return "I have 0 or 1 integer";
}
@Override
public Optional<Integer> get() {
return Optional.of(1);
}
}
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
/**
* Example 2. No common inheritance hierarchy.
*
* <p>Multiple and Single have no common root. So there is no common root to extend!
*
* <p>Gives what we want but not ideal, the {@code getName()} method is now duplicated!
*/
public abstract class _NoCommonRoot {
private _NoCommonRoot() {}
public abstract static class Multiple implements Supplier<Stream<Integer>> {
protected abstract String getName();
}
public abstract static class Single implements Supplier<Optional<Integer>> {
protected abstract String getName();
public final Multiple asMultiple() {
return new Multiple() {
@Override
public Stream<Integer> get() {
return Single.this.get().stream();
}
@Override
public String getName() {
return Single.this.getName();
}
};
}
}
}
public class MultipleInstance extends _NoCommonRoot.Multiple {
@Override
public String getName() {
return "I have 0 or more integer";
}
@Override
public Stream<Integer> get() {
return Stream.of(1);
}
}
public class SingleInstance extends _NoCommonRoot.Single {
@Override
public String getName() {
return "I have 0 or 1 integer";
}
@Override
public Optional<Integer> get() {
return Optional.of(1);
}
}
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
/**
* Example 3. Sealed
*
* <p>Now sealed. Outsiders cannot implement the root abstraction.
*
* <p>(i.e. {@code extends Sealed} is forbidden).
*/
public abstract class Sealed<T> implements Supplier<T> {
// prevent extension via. private constructor
// effectively 'seals' the class like in Scala, Kotlin etc.
private Sealed() {}
protected abstract String getName();
public abstract static class Multiple extends Sealed<Stream<Integer>> {}
public abstract static class Single extends Sealed<Optional<Integer>> {
public final Multiple asMultiple() {
return new Multiple() {
@Override
public Stream<Integer> get() {
return Single.this.get().stream();
}
@Override
public String getName() {
return Single.this.getName();
}
};
}
}
}
public class MultipleInstance extends Sealed.Multiple {
@Override
public String getName() {
return "I have 0 or more integer";
}
@Override
public Stream<Integer> get() {
return Stream.of(1);
}
}
public class SingleInstance extends Sealed.Single {
@Override
public String getName() {
return "I have 0 or 1 integer";
}
@Override
public Optional<Integer> get() {
return Optional.of(1);
}
}
@will-molloy
Copy link
Author

Note the final solution does not provide exhaustiveness of the type (i.e. Sealed), will have to wait for sealed interfaces for that!
https://openjdk.java.net/jeps/8222777

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment