[인프런 워밍업 클럽] BE 0기 6일차 과제

image

컨트롤러)

@RestController
public class FruitController {

    private final FruitService fruitService;

    public FruitController(FruitService fruitService) {
        this.fruitService = fruitService;
    }

    @PostMapping("/api/v1/fruit")
    public void saveFruit(@RequestBody FruitRequest request) {
        fruitService.saveFruit(request);
    }


    @PutMapping("/api/v1/fruit")
    public void saleFruit(@RequestBody SoldOutFruitRequest request) {
        fruitService.saleFruit(request);
    }

    @GetMapping("/api/v1/fruit/stat")
    public TotalPriceResponse salesData(@RequestParam String name) {
        return fruitService.salesData(name);
    }
}

서비스)

@Service
public class FruitService {

    private final FruitRepository fruitRepository;

    public FruitService(FruitRepository fruitRepository) {
        this.fruitRepository = fruitRepository;
    }

    public void saveFruit(FruitRequest request) {
        fruitRepository.saveFruit(request);
    }

    public void saleFruit(SoldOutFruitRequest request) {
        boolean isEmpty = fruitRepository.checkSoldOut(request);

        if (isEmpty) {
            throw new IllegalArgumentException();
        }

        fruitRepository.saleFruit(request);
    }

    public TotalPriceResponse salesData(String name) {
        return new TotalPriceResponse(fruitRepository.salesRead(name), fruitRepository.notSalesRead(name));
    }
}

 

레포지토리 인터페이스)

public interface FruitRepository {

    void saveFruit(FruitRequest request);

    void saleFruit(SoldOutFruitRequest request);

    boolean checkSoldOut(SoldOutFruitRequest request);

    long salesRead(String name);

    long notSalesRead(String name);
}

 

FruitMemoryRepository)

@Primary
@Repository
public class FruitMemoryRepository implements FruitRepository {

    private final List<Fruit> fruits = new ArrayList<>();

    @Override
    public void saveFruit(FruitRequest request) {
        fruits.add(new Fruit(request.getName(), request.getWarehousingDate(), request.getPrice()));
    }

    @Override
    public void saleFruit(SoldOutFruitRequest request) {
        Fruit fruit = fruits.get((int) request.getId());
        fruit.setSold(true);
    }

    @Override
    public boolean checkSoldOut(SoldOutFruitRequest request) {
        Fruit fruit = fruits.get((int) request.getId());
        if (fruit.isSold()) {
            return true;
        }
        return false;
    }

    @Override
    public long salesRead(String name) {
        long price = 0;
        for (int i = 0; i < fruits.size(); i++) {
            Fruit fruit = fruits.get(i);
            if (fruit.getName().equals(name) && fruit.isSold()) {
                price += fruit.getPrice();
            }
        }
        return price;
    }

    @Override
    public long notSalesRead(String name) {
        long price = 0;
        for (int i = 0; i < fruits.size(); i++) {
            Fruit fruit = fruits.get(i);
            if (fruit.getName().equals(name) && !fruit.isSold()) {
                price += fruit.getPrice();
            }
        }
        return price;
    }
}

결과)

image메모리에 저장하는 방식으로서, 서버를 재시작 할때마다 데이터를 입력해 주어야 한다. 초기 데이터 입력으로 사과 5000, 사과 7000, 사과 9000을 입력해주었고, 사과 7000을 판매했을 때 판매 데이터 결과값이다.

 

FruitMySqlRepository)

@Repository
public class FruitMySqlRepository implements FruitRepository {

    private final JdbcTemplate jdbcTemplate;

    public FruitMySqlRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public void saveFruit(FruitRequest request) {
        String sql = "insert into fruit (name, warehousing_date, price) values (?, ?, ?)";
        jdbcTemplate.update(sql, request.getName(), request.getWarehousingDate(), request.getPrice());
    }

    @Override
    public void saleFruit(SoldOutFruitRequest request) {
        String sql = "update fruit set is_sold = true where id = ?";
        jdbcTemplate.update(sql, request.getId());
    }

    @Override
    public boolean checkSoldOut(SoldOutFruitRequest request) {
        String readSql = "select id from fruit where id = ? and is_sold = false";
        return jdbcTemplate.query(readSql, (rs, rowNum) -> 0, request.getId()).isEmpty();

    }

    @Override
    public long salesRead(String name) {
        String salesRead = "select sum(price) price from fruit where name = ? and is_sold = true";
        List<Long> price = jdbcTemplate.query(salesRead, (rs, rowNum) -> rs.getLong("price"), name);

        return price.get(0);
    }

    @Override
    public long notSalesRead(String name) {
        String notSalesRead = "select price from fruit where name = ? and is_sold = false group by price";
        List<Long> price = jdbcTemplate.query(notSalesRead, (rs, rowNum) -> rs.getLong("price"), name);

        return price.get(0);
    }
}

계층구조 리팩토링을 진행한 결과로서, 4일차 과제와 동일한 결과값을 나타내주었다.

이번 리팩토링을 진행함으로서 controller, service, repository 계층별 역할과 책임에 대해 자세히 알게 되었고, 인터페이스를 적용시킬때가 언제 인지를 확실하게 알게 되었다.

 

추가적으로, FruitMemoryRepository에서 스트림, 람다식, 메소드 레퍼런스를 사용해보았다.

    @Override
    public long salesRead(String name) {
        return fruits.stream()
                .filter(fruit -> fruit.getName().equals(name))
                .filter(Fruit::isSold)
                .mapToLong(Fruit::getPrice)
                .sum();
    }

    @Override
    public long notSalesRead(String name) {
        return fruits.stream()
                .filter(fruit -> fruit.getName().equals(name))
                .filter(fruit -> !fruit.isSold())
                .mapToLong(fruit -> fruit.getPrice())
                .sum();
    }

salesRead에서 메소드 레퍼런스를 적용시켰고, notSalesRead에서는 람다식을 이용해서 코드를 작성해보았다.

3일차 과제에서 배웠던 내용을 적용시킴으로 한층 더 발전된 코드가 되었다.

댓글을 작성해보세요.

채널톡 아이콘