While the Strategy interface is in acord with strategy design pattern its implementations are command design pattern since the implementations call behaviours of the reference hold by the field initialised by the constructor. Adding to the method defined by the Strategy interface additional argument to pass the object the field holds reference to could be the solution to avoid the confusion about the design pattern intended to use, that is command pattern since calling behaviour of objects that change their state is the difference between the two conflated in the implementation to review design patterns.
The retainAll method could be improved by defining a command that traverses the string of POJOs removing the POJOs the passed collection doesn’t contain:
private static class RetainAll implements Strategy {
private Of of;
public RetainAll(Of context) { of = context; }
@Override
public boolean element(Object element) {
Collection retaineds = (Collection) element;
boolean result = false;
Bind bind = of.bindings;
while (!of.isEmpty() && bind != null) {
if (!retaineds.contains(bind.element)) {
bind = bind == of.bindings ? of.peakless()
: Of.remove(bind, bind.next);
result = true;
} else {
bind = bind.next;
}
}
return result;
}
}
private static class Strategies {
private Strategy prepend, append,containsNull, contains, peakless
, nullPeakless, nullless, remove, allNullPeakless
, allPeakless,lastRemove, lastNullRemove, allless
, allNullless, retainAll;
public Strategies(Of of) {
prepend = new Prepend(of);
append = new Append(of);
peakless = new Peakless(of);
nullPeakless = new NullPeakless(of);
nullless = new Nullless(of);
remove = new Remove(of);
allless = new Allless(of);
allNullless = new AllNullless(of);
allNullPeakless = new AllNullPeakless(of);
allPeakless = new AllPeakless(of);
lastRemove = new LastRemove(of);
lastNullRemove = new LastNullRemove(of);
containsNull = new ContainsNull(of);
contains = new Contains(of);
retainAll = new RetainAll(of);
}
public Strategy append() { return append; }
public Strategy prepend() { return prepend; }
public Strategy peakless(Object removed) {
return removed == null ? nullPeakless : peakless;
}
public Strategy remove(Object removed) {
return removed == null ? nullless : remove;
}
public Strategy allPeakless(Object removed) {
return removed == null ? allNullPeakless : allPeakless;
}
public Strategy allless(Object removed) {
return removed == null ? allNullless : allless;
}
public Strategy lastRemove(Object removed) {
return removed == null ? lastNullRemove : lastRemove;
}
public Strategy contains(Object contained) {
return contained == null ? containsNull : contains;
}
public Strategy retainAll() { return retainAll; }
}
...changes that would turn the implementation of retainAll method to:
@Override
public boolean retainAll(Collection<?> c) {
if (c.isEmpty() || isEmpty()) { return false; }
return strategies.retainAll().element(c);
}
Although the purpose of the requested review is the java.util.Deque implementation could be helpful to know the Bulk and TimedBulk explorers, from the usage showcase code snippet, print twice the summary of the last exploration, while TimedState runner prints the result, when that is false, and the summary when the result is true.
Code snippet attempting to change mentioned behaviours:
private static class TimedState implements Runner {
private String text;
private long start, elapsed;
public TimedState(String explored) {
text = explored;
start = System.nanoTime();
}
@Override
public void summary(boolean result) {
elapsed = (System.nanoTime() - start) / 1000;
}
public void print(boolean result) {
String string = result ? "Passed" : "Failed";
String message = text + " ... " + string
+ " [elapsed: " + elapsed + " ms]";
if (result) {
System.out.println(message);
} else {
System.err.println(message);
}
}
}
private static class Bulk implements Explorer {
private Plain[] runners = {};
private boolean[] results = {};
public void of(String text) { run(new Plain(text)); }
public void run(Plain runner) { runners = append(runner, runners); }
private Plain[] append(Plain runner, Plain ... runners) {
Plain[] runees = new Plain[runners.length + 1];
runees[runees.length - 1] = runner;
for (int i = 0; i < runees.length - 1; i++) {
runees[i] = runners[i];
}
return runees;
}
@Override
public void summary(boolean result) {
boolean[] booleans = new boolean[results.length + 1];
booleans[booleans.length - 1] = result;
for (int i = 0; i < results.length; i++) {
booleans[i] = results[i];
}
results = booleans;
}
@Override
public void overall() {
if (results.length == 0) { return; }
int index = results.length - 1;
boolean passed = results[index];
for (int i = index; i > -1; i--) {
passed = passed && results[i];
runners[i].summary(results[i]);
}
overall(passed);
}
@Override
public void overall(boolean result) {
if (result) {
System.out.println();
System.out.println("Pass.");
} else {
System.err.println();
System.err.println("Fail.");
}
}
}
private static class TimedBulk implements Explorer {
private TimedState[] runners = {};
private boolean[] results = {};
public void of(String text) { run(new TimedState(text)); }
public void run(TimedState runee) { runners = append(runee, runners); }
private TimedState[] append(TimedState runner, TimedState ... runners) {
TimedState[] runees = new TimedState[runners.length + 1];
runees[runees.length - 1] = runner;
for (int i = 0; i < runees.length - 1; i++) {
runees[i] = runners[i];
}
return runees;
}
@Override
public void summary(boolean result) {
boolean[] booleans = new boolean[results.length + 1];
booleans[booleans.length - 1] = result;
for (int i = 0; i < results.length; i++) {
booleans[i] = results[i];
runners[i].summary(result);
}
results = booleans;
}
@Override
public void overall() {
if (results.length == 0) { return; }
int index = results.length - 1;
boolean passed = results[index];
for (int i = index; i > -1; i--) {
passed = passed && results[i];
runners[i].print(results[i]);
}
overall(passed);
}
@Override
public void overall(boolean result) {
if (result) {
System.out.println();
System.out.println("Pass.");
} else {
System.err.println();
System.err.println("Fail.");
}
}
}