ImageServicepackage com.outstagram.outstagram.service;
import com.outstagram.outstagram.dto.ImageDTO;
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
public interface ImageService {
void saveImages(List<MultipartFile> imgFiles, Long postId);
List<ImageDTO> getImages(Long postId);
void deleteByIds(List<Long> deleteImgIds);
}
ImageServieLocal@Slf4j
@Service
@RequiredArgsConstructor
public class ImageServiceLocal implements ImageService {
...
}
자신보다 변하기 쉬운 것에 의존하지 마라
컨트롤러는 변하기 쉬운 로컬 저장 서비스에 의존하지 않고 인터페이스 서비스에 의존
컨트롤러 입장에서는 이미지 저장 인터페이스 덕분에 하위 구현체가 바뀌어도(로컬 저장 서비스 -> S3 저장 서비스) 영향이 없다
이미지 저장 인터페이스는 확장에 열려 있고, 컨트롤러 입장에서는 주변의 변화에 폐쇄되어 있음
다른 서비스 계층(PostService, UserService)은 추후에 변경될 일이 없다. 그래서 따로 Service 계층을 인터페이스화 하지 않았다
ImageService 인터페이스를 구현하는 ImageSeviceAwsS3 클래스를 구현@Service
@RequiredArgsConstructor
public class ImageSeviceAwsS3 implements ImageService {
...
}
ImageService 인터페이스의 구현체로 ImageSeviceAwsS3 클래스를 사용하겠다고 설정@Configuration
public class ServiceConfig {
@Bean
@Profile("local")
public ImageService imageServiceLocal() {
return new ImageServiceLocal();
}
@Bean
@Profile("prod")
public ImageService imageServiceS3(AmazonS3 amazonS3) {
return new ImageServiceS3(amazonS3);
}
}
이 코드는 로컬에서는 ImageServiceLocal 구현체를 사용하고
실제 prod 환경에서는 ImageServiceAwsS3 구현체를 사용하겠다고 설정한 코드
➡ 따로 코드를 수정할 것 없이, S3에 저장하는 로직 구현하고 이를 @Bean으로 등록하면 된다

추후에 S3가 아니더라도 다른 위치에 저장하게 되더라도 해당 로직 구현하고 config에 설정만 해주면 된다
컨트롤러의 이미지 저장 코드는 전혀 수정하지 않고 로직을 변경할 수 있다
이를 통해, 유지보수성이 상당히 올라감
최근에 이론적으로 DIP, OCP 등 객체지향의 5대원칙을 공부했었다.
실제로 내 프로젝트에 해당 원칙을 적용해보니 제대로 이해가 간다.
역시 코드로 느껴야 돼...
추후에 해당 구조에서도 겹치는 코드가 많아서 템플릿 메서드 패턴 도입함... ㅎㅎ
여기서 더 발전된 패턴 볼 수 있음!