import java.util.*; interface AncTree { abstract int size( /* AncTree this */ ); //abstract List allNames(); abstract AncTree changeName( /* AncTree this, */ String name1, String name2 ); /* Representing union-types by using classes * is called the 'composite design pattern'. * (And usually it's not recognized that they're taking the * union of two different types(sets).) * See for example: * http://sourcemaking.com/design_patterns/composite */ List allNames( /* AncTree this */ ); default boolean containsName( /* AncTree this, */ String target ) { return this.allNames().contains( target ); } /* Question: should this be an abstract class, or an interface? * Well, probably an interface. * (We're using `main` for test cases; we'd have to put tests into * their own class if we made this an interface.) * But what if there was some operation that could be entirely * written out of others? * For example, if I have abstract `allNames`, * then I can write (non-abstractly) `containsName`: */ //abstract boolean containsName( /* AncTree this, */ String target ); /* These sort of functions aren't uncommon. * Happily, in Java 8, interfaces CAN include such code (yay!). * So use an interface, and provide `default` on methods which only call * other methods already in the interface. * * Old school sol'n (pre Java-8): * Have an interface *and* an abstract class. * interface IAncTree {...} * abstract class AncTree implements IAncTree {...} * class Child extends AncTree {...} * class Unknown extends AncTree {...} */ //abstract List allNames( /* AncTree this */ ); /** Some test cases for AncTrees. * @param args -- ignored. */ public static void main( String[] args ) { AncTree abe = new Child( "Abe", 1920, "brown", new Unknown(), new Unknown() ); AncTree mona = new Child( "Mona", 1929, "blue", new Unknown(), new Unknown() ); AncTree homer = new Child( "Homer", 1955, "brown", mona, abe ); AncTree bart = new Child( "Bart", 1982, "brown", new Child( "Marge", 1953, "blue", new Child( "Jackie", 1926, "brown", new Unknown(), new Unknown() ), new Unknown() ), homer ); System.out.println( "HAHA: " + homer.changeName("Abe","Lincoln") ); System.out.println( "Actual: " + (new Unknown()).size() ); System.out.println( "Expect: " + 0); System.out.println( "Actual: " + abe.size() ); System.out.println( "Expect: " + 1); System.out.println( "Actual: " + homer.size() ); System.out.println( "Expect: " + 3); System.out.println( "Actual: " + bart.size() ); System.out.println( "Expect: " + 6); /* System.out.println( "Actual: " + homer.allNames() ); System.out.println( "Expect: " + java.util.Arrays.asList("Mona","Homer","Abe") ); System.out.println( "Actual: " + bart.allNames() ); System.out.println( "Expect: " + java.util.Arrays.asList("Jackie", "Marge", "Bart", "Mona","Homer","Abe") ); */ //System.out.println( "Actual: " + homer.entitle() ); //System.out.println( "Expect: " + homer.entitle() ); /* System.out.println( "Actual: " + abe.toString() ); System.out.println( "Expect: " + "new Child( \"Abe\", 1920, \"brown\", new Unknown(), new Unknown() )" ); System.out.println( "Actual: " + homer.toString() ); System.out.println( "Expect: " + "??" ); */ } }