This is because there may be a relation but there is no must for a relation.
Example:
First we have a Command
interface
public interface Command {
void execute();
}
with some implentations...
public class CopyFilesCommand implements Command {
@Override
public void execute() {
// copy some files
}
}
public class ZipFilesCommand implements Command {
@Override
public void execute() {
// collect the copied files to a zip archive
}
}
public class MailZipFileCommand implements Command {
@Override
public void execute() {
// mail the zip file to some address
}
}
now imagine a server application with a basic configuration
public class Config {
private static final Config INSTANCE = new Config();
private List<Command> commands = new ArrayList<>();
private Config() {
// intentionally empty
}
public static List<Command> getCommands() {
return Collections.unmodifiableList(INSTANCE.commands);
}
public static void addCommand(Command command) {
INSTANCE.commands.add(command);
}
}
a client Method can now set up the configuration like this
public class Client {
public void setUpConfig() {
Config.addCommand(new CopyFilesCommand());
Config.addCommand(new ZipFilesCommand());
Config.addCommand(new MailZipFileCommand());
}
}
and some service running inside our server application could then take the commands and invoke them
public class Invoker implements Runnable {
@Override
public void run() {
for (Command command : Config.getCommands()) {
command.execute();
}
}
}
you see Client and Invoker do not know each other (i.e. they do not have a relation) but still work together using the commands they both know.