Skip to content

Instantly share code, notes, and snippets.

@ramsayleung
Created April 21, 2024 22:26
Show Gist options
  • Save ramsayleung/cb5bda3416cf605dcb00737449853961 to your computer and use it in GitHub Desktop.
Save ramsayleung/cb5bda3416cf605dcb00737449853961 to your computer and use it in GitHub Desktop.
Solution for Unix Find command OOD design
package ramsayleung.github.io.ood;
// Problem statement:
// Design Unix File Search API to search file with different arguments as "extension", "name", "size" ...
// The design should be maintainable to add new contraints.
//
// Follow up: How would you handle if some contraints should support AND, OR conditionals.
import java.util.ArrayList;
import java.util.List;
class File {
String name;
int size;
int type;
boolean isDirectory;
List<File> children;
public File(String name, int size, int type, boolean isDirectory, List<File> children) {
this.name = name;
this.size = size;
this.type = type;
this.isDirectory = isDirectory;
this.children = children;
}
}
interface Filter {
boolean apply(final File file);
}
class ExtensionFilter implements Filter{
private String extension;
public ExtensionFilter(String extension) {
this.extension = extension;
}
@Override
public boolean apply(File file) {
return file.name.endsWith(extension);
}
}
class NameFilter implements Filter {
private String name;
public NameFilter(String name) {
this.name = name;
}
@Override
public boolean apply(File file) {
return file.name.equals(name);
}
}
class MinSizeFilter implements Filter {
private final int minSize;
public MinSizeFilter(int minSize) {
this.minSize = minSize;
}
@Override
public boolean apply(File file) {
return file.size > minSize;
}
}
class MaxSizeFilter implements Filter {
private final int maxSize;
public MaxSizeFilter(int maxSize) {
this.maxSize = maxSize;
}
@Override
public boolean apply(File file) {
return file.size < maxSize;
}
}
class TypeFilter implements Filter {
private final int type;
public TypeFilter(int type) {
this.type = type;
}
@Override
public boolean apply(File file) {
return file.type == type;
}
}
abstract class LogicalFilter implements Filter{
protected final List<Filter> filterList;
LogicalFilter(List<Filter> filterList) {
this.filterList = filterList;
}
}
class AndFilter extends LogicalFilter {
AndFilter(List<Filter> filterList) {
super(filterList);
}
@Override
public boolean apply(File file) {
return filterList.stream().allMatch(filter -> filter.apply(file));
}
}
class OrFilter extends LogicalFilter {
OrFilter(List<Filter> filterList) {
super(filterList);
}
@Override
public boolean apply(File file) {
return filterList.stream().anyMatch(filter -> filter.apply(file));
}
}
public class FindCommand {
public static List<File> find(File root, List<Filter> filters){
List<File> result = new ArrayList<>();
if(filters.stream().allMatch(filter -> filter.apply(root))) {
result.add(root);
}
find(root, filters, result);
return result;
}
private static void find(File directory, List<Filter> filters, List<File> result) {
if(directory.children.isEmpty()){
return;
}
for(File file: directory.children){
if(file.isDirectory){
find(file, filters, result);
}else {
boolean isMatched = filters.stream().allMatch(filter -> filter.apply(file));
if(isMatched){
result.add(file);
}
}
}
}
public static void main(String[] args) {
File root = new File("home", 100, 0, true, new ArrayList<>());
File subFile1 = new File("foo", 140, 1, false, new ArrayList<>());
File subFile2 = new File("bar.bak", 180, 2, false, new ArrayList<>());
root.children.addAll(List.of(subFile1, subFile2));
List<Filter> filters1 = List.of(new AndFilter(List.of(new NameFilter("home"), new MinSizeFilter(110))));
List<File> result1 = FindCommand.find(root, filters1); // should be empty
System.out.println(result1.size());
List<Filter> filters2 = List.of(new OrFilter(List.of(new NameFilter("home"), new TypeFilter(0))));
List<File> result2 = FindCommand.find(root, filters2); // should return "home"
System.out.println(result2.size());
System.out.println(result2.getFirst().name);
List<Filter> filters3 = List.of(new AndFilter(List.of(new ExtensionFilter("bak"), new MinSizeFilter(150))));
List<File> result3 = FindCommand.find(root, filters3); // should return "bar.bak"
System.out.println(result3.size());
System.out.println(result3.getFirst().name);
List<Filter> filters4 = List.of(new AndFilter(List.of(new MinSizeFilter(130), new MaxSizeFilter(150))));
List<File> result4 = FindCommand.find(root, filters4); // should return "foo"
System.out.println(result4.size());
System.out.println(result4.getFirst().name);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment