변경되는 고객의 요구사항에 대해서 어떻게 유연하게 대처해야하는지 하단의 코드를 통해 확인해보자

도메인

고객의 정보를 담고 있는 데이터들

public enum Gender {
    MALE, FEMALE;
}

public class Customer {
    private String name;
    private int age;
    private Gender gender;

    public Customer(int age, String name, Gender gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("이름 : " + name + ", ");
        builder.append("나이 : " + age + ", ");
        builder.append("성별 : " + gender.name());
        return builder.toString();
    }

    // getter, equals ...
}

요구사항

  • 고객의 나이가 30대 이상인 사람들을 찾고 싶다.
public class SearchCustomer {
    private List<Customer> customers;

    public SearchCustomer(List<Customer> customers) {
        this.customers = customers;
    }

    public List<Customer> searchByAge(int age) {
        List<Customer> result = new ArrayList<>();
        for (Customer customer : customers) {
            if (customer.getAge() >= age) {
                result.add(customer);
            }
        }
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        SearchCustomer searchCustomer = new SearchCustomer(init());
        // 이름 : 홍길동, 나이 : 30, 성별 : MALE
        // 이름 : 김개똥, 나이 : 35, 성별 : MALE
        searchCustomer.searchByAge(30); 
    }

    public static List<Customer> init() {
        List<Customer> customers = new ArrayList();
        customers.add(new Customer(30, "홍길동", Gender.MALE));
        customers.add(new Customer(35, "김개똥", Gender.MALE));
        customers.add(new Customer(25, "아무개", Gender.FEMALE));
        customers.add(new Customer(28, "이순신", Gender.MALE));
        customers.add(new Customer(20, "강남", Gender.FEMALE));
        customers.add(new Customer(21, "이상순", Gender.MALE));
        return customers;
    }

    public static void printCustomer(List<Customer> result) {
        result.forEatch(System.out::println);
    }
}
  • 이름에 성씨가 이씨인 사람들을 찾고 싶다.
public class SearchCustomer {
    private List<Customer> customers;

    public SearchCustomer(List<Customer> customers) {
        this.customers = customers;
    }
    
    public List<Customer> searchByAge(int age) {
        List<Customer> result = new ArrayList<>();
        for (Customer customer : customers) {
            if (customer.getAge() >= age) {
                result.add(customer);
            }
        }
        return result;
    }

    public List<Customer> searchByName(String name) {
        List<Customer> result = new ArrayList<>();
        for (Customer customer : customers) {
            if (customer.getName().startsWith(name)) {
                result.add(customer);
            }
        } 
        return result;
    }
}


public class Main {
    public static void main(String[] args) {
        SearchCustomer searchCustomer = new SearchCustomer(init());
        // 이름 : 이순신, 나이 : 28, 성별 : MALE
        // 이름 : 이상순, 나이 : 21, 성별 : MALE
        searchCustomer.searchByName("이"); 
    }

    public static List<Customer> init() {
        List<Customer> customers = new ArrayList();
        customers.add(new Customer(30, "홍길동", Gender.MALE));
        customers.add(new Customer(35, "김개똥", Gender.MALE));
        customers.add(new Customer(25, "아무개", Gender.FEMALE));
        customers.add(new Customer(28, "이순신", Gender.MALE));
        customers.add(new Customer(20, "강남", Gender.FEMALE));
        customers.add(new Customer(21, "이상순", Gender.MALE));
        return customers;
    }

    public static void printCustomer(List<Customer> result) {
        result.forEatch(System.out::println);
    }
}
  • 여성 회원인 경우만 확인하고 싶다.
public class SearchCustomer {
    private List<Customer> customers;

    public SearchCustomer(List<Customer> customers) {
        this.customers = customers;
    }
    
    public List<Customer> searchByAge(int age) {
        List<Customer> result = new ArrayList<>();
        for (Customer customer : customers) {
            if (customer.getAge() >= age) {
                result.add(customer);
            }
        }
        return result;
    }

    public List<Customer> searchByName(String name) {
        List<Customer> result = new ArrayList<>();
        for (Customer customer : customers) {
            if (customer.getName().startsWith(name)) {
                result.add(customer);
            }
        } 
        return result;
    }

    public List<Customer> searchByGender(Gender gender) {
        List<Customer> result = new ArrayList<>();
        for (Customer customer : customers) {
            if (customer.getGender().equals(gender)) {
                result.add(customer);
            }
        } 
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        SearchCustomer searchCustomer = new SearchCustomer(init());
        // 이름 : 아무개, 나이 : 25, 성별 : FEMALE
        // 이름 : 강남, 나이 : 20, 성별 : FEMALE
        searchCustomer.searchByGender(Gender.FEMALE); 
    }

    public static List<Customer> init() {
        List<Customer> customers = new ArrayList();
        customers.add(new Customer(30, "홍길동", Gender.MALE));
        customers.add(new Customer(35, "김개똥", Gender.MALE));
        customers.add(new Customer(25, "아무개", Gender.FEMALE));
        customers.add(new Customer(28, "이순신", Gender.MALE));
        customers.add(new Customer(20, "강남", Gender.FEMALE));
        customers.add(new Customer(21, "이상순", Gender.MALE));
        return customers;
    }  

    public static void printCustomer(List<Customer> result) {
        result.forEatch(System.out::println);
    }
}

유연한 변화

위의 코드들은 고객의 요구사항에 대해 함수를 하나하나씩 추가하고 있다.

이것을 어떠한 요구사항에도 변경가능하게끔 만들 수는 없을까? 아래의 코드를 보자.

public interface SearchFilter {
    boolean isMatch(Customer customer);
}

public class SearchCustomer {
    private List<Customer> customers;

    public SearchCustomer(List<Customer> customers) {
        this.customers = customers;
    }

    public List<Customer> search(SearchFilter filter) {
        List<Customer> result = new ArrayList<>();
        for (Customer customer : customers) {
            if (filter.isMatch(customer)) {
                result.add(customer);
            }
        }
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        SearchCustomer searchCustomer = new SearchCustomer(init());
        
        // 익명함수
        // 이름 : 홍길동, 나이 : 30, 성별 : MALE
        // 이름 : 김개똥, 나이 : 35, 성별 : MALE
        List<Customer> result = searchCustomer.search(new SearchFilter() {
            @Override
            public boolean isMatch(Customer customer) {
                return customer.getAge() >= 30;
            }
        });

        // 람다
        // 이름 : 이순신, 나이 : 28, 성별 : MALE
        // 이름 : 이상순, 나이 : 21, 성별 : MALE
        List<Customer> result = searchCustomer.search(customer -> customer.getGender().equals(Gender.MALE) && customer.getAge() < 30);

        printCustomer(result);
    }

    public static List<Customer> init() {
        List<Customer> customers = new ArrayList();
        customers.add(new Customer(30, "홍길동", Gender.MALE));
        customers.add(new Customer(35, "김개똥", Gender.MALE));
        customers.add(new Customer(25, "아무개", Gender.FEMALE));
        customers.add(new Customer(28, "이순신", Gender.MALE));
        customers.add(new Customer(20, "강남", Gender.FEMALE));
        customers.add(new Customer(21, "이상순", Gender.MALE));
        return customers;
    }  

    public static void printCustomer(List<Customer> result) {
        result.forEatch(System.out::println);
    }
}
  • 흔히 Main메소드를 client라고 부른다.

이와 같이 하나의 인터페이스를 추가함으로써, 어떠한 조건이든 클라이언트의 요구사항에 따라 유연하게 데이터를 제공할 수 있게 되었다.

마지막으로 stream()을 사용하여 마지막 리팩토링 작업을 하겠다. 아래의 코드를 보자.

@FunctionalInterface
public interface SearchFilter {
    boolean isMatch(Customer customer);
}

public class SearchCustomer {
    private List<Customer> customers;

    public SearchCustomer(List<Customer> customers) {
        this.customers = customers;
    }

    public List<Customer> search(SearchFilter filter) {
        return customers.stream()
                .filter(filter::isMatch())
                .collect(Collectors.toList());
    }
}

public class Main {
    public static void main(String[] args) {
        SearchCustomer searchCustomer = new SearchCustomer(init());
        
        // 람다
        // 이름 : 이순신, 나이 : 28, 성별 : MALE
        // 이름 : 이상순, 나이 : 21, 성별 : MALE
        List<Customer> result = searchCustomer.search(customer -> customer.getGender().equals(Gender.MALE) && customer.getAge() < 30);

        printCustomer(result);
    }

    public static List<Customer> init() {
        List<Customer> customers = new ArrayList();
        customers.add(new Customer(30, "홍길동", Gender.MALE));
        customers.add(new Customer(35, "김개똥", Gender.MALE));
        customers.add(new Customer(25, "아무개", Gender.FEMALE));
        customers.add(new Customer(28, "이순신", Gender.MALE));
        customers.add(new Customer(20, "강남", Gender.FEMALE));
        customers.add(new Customer(21, "이상순", Gender.MALE));
        return customers;
    }  

    public static void printCustomer(List<Customer> result) {
        result.forEatch(System.out::println);
    }
}

해당 코드들을 보고 생각한 후, 언제든 바뀔 수 있는 요구사항에 대해 더욱더 유연하게 대처할 수 있도록 대비하자!

댓글남기기