As for the organization, you might want to unify object contracts, which you find similar:
public interface FSFilter{ public boolean accept(FSNode node); } public interface FSNode { public String getPath(); public FSNode getParent(): public Volume getVolume(); public boolean isFile(); public boolean isFolder(); public boolean isVolume(); public boolean exists(); public boolean delete(); public List<FSNode> getSubNodes(boolean recursive, int depth, FSFilter filter); public int deleteSubNodes(boolean recursive, int depth, FSFilter filter); public long getSize(boolean recursive, int depth, FSFilter filter); }
The above methods with various combinations of parameters would provide most of the operations that may be required from the file system tree. To add certain functions to certain types of file system objects, you can provide an implementation for each of them. For example, the Volume class may have an additional diskUsage() method, and the File class may have getInputStream() , etc.
public class File implements FSNode {
Then you can put all the utility logic that applies to all of them as a static function without saving, for example, a recursive list of files, deletion, creation and modification. Since these operations usually concern basic OS calls. These will be the equivalent of OS commands, such as ls , rm , mount , etc., in your program. The above implementations will call these utility functions internally. In addition, most of the complex file system code will be located here:
public final class FSUtil{ public static List<FSNode> list(boolean recursive, int depth, FSFilter filter){
For reference, you can look at existing implementations such as apache.commons.io .