After Java 8, we often see this controversy about saying that some classic Patterns have become obsolete. A Pattern encodes what is considered best practice for a type of problem, but not all practice is eternally the best and can be replaced or constantly improved. It is still important to know the problems that each Pattern proposes to solve, even if an improvement in implementation is possible.
The very Gang of Four considers that the chosen programming language influences how Pattern will be implemented, being easier or more difficult depending on the features that the language offers: "In Fact, there are enough Differences between Smalltalk and C++ to Mean that some Patterns can be Expressed more easily in one language than the other. (See Iterator for example.)"
The book Java 8 Lambdas: Pragmatic Functional Programming describes some Patterns improved by Java 8. For example, Pattern Observer, in simpler cases, you can dispense with the implementation of the classes that implement the interface that defines an observer. These classes are replaced by Java 8 functions. Pattern has been greatly simplified, but the problem still exists and Pattern also.
To illustrate the simplification in the Pattern Observer, consider the following interface to be implemented by organizations that wish to observe who lands on the moon. In this example, aliens and NASA will be observers.
public interface LandingObserver {
public void observeLanding(String name);
}
The subject is the Moon:
public class Moon {
private final List<LandingObserver> observers = new ArrayList<>();
public void land(String name) {
for(LandingObserver observer : observers) {
observer.observeLanding(name);
}
}
public void startSpying(LandingObserver observer) {
observers.add(observer);
}
}
The following are the deployments of the observers representing the aliens and NASA and responding to the event of a moon landing.
Aliens:
public class Aliens implements LandingObserver {
@Override
public void observeLanding(String name) {
if(name.contains("Apollo")) {
System.out.println("They're distracted, lets invade earth!");
}
}
}
NASA:
public class Nasa implements LandingObserver {
@Override
public void observeLanding(String name) {
if(name.contains("Apollo")) {
System.out.println("We made it!");
}
}
}
The client code is usually, for example:
Moon moon = new Moon();
moon.startSpying(new Nasa());
moon.startSpying(new Aliens());
moon.land("An asteroid");
moon.land("Apollo 11");
Using both the Aliens and NASA classes, shown earlier, are unnecessary. In this case, the client is something like:
Moon moon = new Moon();
moon.startSpying(name -> {
if(name.contains("Apollo"))
System.out.println("We made it!");
});
moon.startSpying(name -> {
if(name.contains("Apollo"))
System.out.println("They're distracted, lets invade earth!");
});
moon.land("An asteroid");
moon.land("Apollo 11");
Man, I got a feeling you’re coming to help, for real. If you think, for example, of Optional<T>, it seems to me that it will facilitate some validation Controls, such as Chains of Responsability. In this case, we can use orelse(...) to perform the chaining, for example.
– Jean Coppieters
In fact, I think that when we pass to organizational Patterns (is that the term?) Java 8 can break a little. Thinking of Gof’s, I think at best he simplifies, you know,?
– Jean Coppieters