[Spring] Service, ServiceImpl ์˜ ๊ด€๊ณ„ (feat. OCP)

2022. 2. 2. 20:39ใ†Backend/๐ŸŒฟ Spring

๋ฌธ์ œ ์ธ์ง€

ํšŒ์‚ฌ์—์„œ ๊ฐœ๋ฐœ์ค‘์ธ spring boot ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋ฅผ ๋ณด๋ฉด์„œ Service layer ์˜ impl ํด๋”์™€ interface ๊ฐ€ ๋ˆˆ์— ๊ณ„์† ๋ฐŸํ˜”์Šต๋‹ˆ๋‹ค. ๋ณธ๋”” ์ž๋ฐ”์—์„œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ๊ฐ์ฒด์ง€ํ–ฅ ํŠน์ง• ์ค‘ ํ•˜๋‚˜์ธ ๋‹คํ˜•์„ฑ ์ž…๋‹ˆ๋‹ค.

 

๋‹คํ˜•์„ฑ: ํ•˜๋‚˜์˜ ์ž๋ฃŒํ˜•์— ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ฐ์ฒด๋ฅผ ๋Œ€์ž…ํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์–ด๋‚ด๋Š” ์„ฑ์งˆ

 

๊ทธ๋Ÿฐ๋ฐ ์œ„์˜ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด ํ•˜๋‚˜์˜ ์ž๋ฃŒํ˜•(Interface ICSA2010Service)์— ๋Œ€ํ•˜์—ฌ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•˜๋‚˜์š”? ์•„๋‹™๋‹ˆ๋‹ค. ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„์ฒด๋Š” impl ํŒจํ‚ค์ง€ ํ•˜์œ„์— ํ•˜๋‚˜ ๋ฐ–์— ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰ 1:N ๊ด€๊ณ„๊ฐ€ ์•„๋‹Œ 1:1์˜ ๊ด€๊ณ„๋ฅผ ํ˜•์„ฑํ•˜๋ฉด์„œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉ์ค‘์ธ ๊ฒƒ์ด์ฃ . 

 

 

OCP ์— ์ž…๊ฐํ•œ ์ฝ”๋“œ์ด๊ธด ํ•˜๋‚˜,, ์˜๋„๋ฅผ ์•Œ๊ณ  ์“ฐ๋Š” ๊ฒƒ์ธ๊ฐ€?

 

์‚ฌ์‹ค ์ด๊ฒŒ ์ž˜๋ชป ๋œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. OCP ์›์น™์— ์ž…๊ฐํ•˜์—ฌ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„์ฒด๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด, ํŠน์ • ๊ธฐ์ˆ ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•˜๋”๋ผ๋„, ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ(ํ˜ธ์ถœ ์˜์—ญ)๋Š” ์ˆ˜์ •ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„์ฒด๊ฐ€ 1 : N ๊ด€๊ณ„ ์ผ ๋•Œ ํ•ด๋‹นํ•˜๋Š” ๋ง์ด์ฃ . 

 

 

ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ์ ํŠธ์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, interface ์™€ ๊ตฌํ˜„์ฒด ํด๋ž˜์Šค๋Š” 1:1๋กœ ๊ตฌ์„ฑ๋˜์–ด, ์‹ค์งˆ์ ์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐˆ์•„๋ผ์šฐ๋Š” ์ƒํ™ฉ์ด ๊ทธ๋‹ค์ง€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ํ”„๋กœ์ ํŠธ, ๋‹น์žฅ ํšŒ์‚ฌ ํ”„๋กœ์ ํŠธ์—์„œ๋„ ๊ด€์Šต์ ์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹Œ๊ฐ€ ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. 

 

๊ด€์Šต์ ์ธ ์ถ”์ƒํ™”์˜ ์žฅ์ ๊ณผ ๋‹จ์ 

์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„์ฒด๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์€ ๊ตฌํ˜„์ฒด ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ํ™•์žฅํ•˜๋”๋ผ๋„, ์ด๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.

 

์ข€ ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ํ˜ธ์ถœ๋ถ€๋ผ ๋ถ€๋ฅธ๋‹ค๋ฉด, Service Layer ์ž…์žฅ์—์„œ๋Š” ์„œ๋น„์Šค ํด๋ž˜์Šค๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Service layer ์˜ ๊ตฌํ˜„์ฒด ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ๊ต์ฒดํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. (ex, AServiceImpl -> BServiceImpl)

ํด๋ผ์ด์–ธํŠธ์ธ ์ปจํŠธ๋กค๋Ÿฌ ์ž…์žฅ์—์„œ๋Š” ์–ด์ฐจํ”ผ ์˜์กด์ฃผ์ž…ํ•˜๋Š” ํƒ€์ž…์€ IService ๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๊ณ , ์—ฌ๊ธฐ์— ์ •์˜๋œ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋Š” ๋ณ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

์ธํ„ฐํŽ˜์ด์Šค

// Interface

public interface IService {

    String test();

}

 

๊ตฌํ˜„์ฒด

@Service
public class AServiceImpl implements IService {

    @Override
    public String test() {
        return "AServiceImpl";
    }

}

 

์ปจํŠธ๋กค๋Ÿฌ

// Controller 

@RequiredArgsConstructor
@RestController
public class SampleController {

    private final IService service;

    @GetMapping("/test")
    public String test(){
        return service.test();
    }

}

 

์œ„ ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์ปจํŠธ๋กค๋Ÿฌ๋Š” ํŠน์ • ๊ตฌํ˜„์ฒด๊ฐ€ ์•„๋‹Œ IService ํƒ€์ž…์„ ์˜์กด ์ฃผ์ž…๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. (๋ฌผ๋ก  ํŠน์ • ๊ตฌํ˜„์ฒด์ธ AServiceImpl ์„ ์˜์กด์ฃผ์ž… ๋ฐ›์•„๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.)

์ด๋ ‡๊ฒŒ ๊ตฌํ˜„์ฒด๊ฐ€ ์•„๋‹Œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์˜์กด๋ฐ›์œผ๋ฉด OCP ์›์น™์„ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌด์Šจ ๋œป์ธ์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ๋‹ค๋ฉด ์ž„์˜๋กœ BServiceImpl ๊ตฌํ˜„์ฒด๋ฅผ ์ถ”๊ฐ€ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

๋˜ ๋‹ค๋ฅธ ๊ตฌํ˜„์ฒด (BServiceImpl)

public class BServiceImpl implements IService {

    @Override
    public String test() {
        return "BServiceImpl";
    }

}

AServiceImpl ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ IService์— ์„ ์–ธ๋œ test() ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ด ํด๋ž˜์Šค์— @Service ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ด๋ฉด ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ์˜ํ•ด SampleController ๋กœ ์˜์กด์ฃผ์ž…์ด ๋ฉ๋‹ˆ๋‹ค. ( AServiceImpl ์˜ @Service ์–ด๋…ธํ…Œ์ด์…˜์€ ์ œ๊ฑฐํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.)

 

๋Š๋‚Œ์ด ์˜ค์‹œ๋‚˜์š”? 

IService ๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌ์ฒดํ™” ํ•˜๋Š” ๊ตฌํ˜„์ฒด๊ฐ„์˜(AServiceImpl, BServiceImpl) ์ฐจ์ด๋งŒ ์žˆ์„ ๋ฟ, ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ(์ปจํŠธ๋กค๋Ÿฌ) ์ž…์žฅ์—์„œ๋Š” ๋ฌด์—‡์ด ๋ณ€ํ–ˆ๋Š”์ง€ ์ „ํ˜€ ๋ชจ๋ฅด๋Š” ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ชจ๋ฅด๋Š” ์ƒํƒœ๋ผ๋Š” ๊ฒƒ์€, ServiceLayer ์˜ ๊ตฌํ˜„์ฒด๊ฐ€ ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋Š” ์ „ํ˜€ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ ๋‹จ์ˆœํžˆ test() ๋ผ๋Š” ๋ฉ”์„œ๋“œ์—์„œ ๋ฌธ์ž์—ด์„ ์ถœ๋ ฅํ•˜๋Š” ๊ธฐ๋Šฅ๋ฐ–์— ์—†์–ด ๊ฐํฅ์ด ์—†์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ ๋ช…ํ•œ ์˜ˆ์ œ์ธ ์ •๋ฅ  ํ• ์ผ(%ํ• ์ธ) ์ •์•ก ํ• ์ธ(1000์› ํ• ์ธ) ์„ ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค. ๋งŒ์•ฝ ํ˜„์žฌ๋Š” ์ •๋ฅ  ํ• ์ธ์„ ์ง„ํ–‰ํ•˜๋”๋ผ๋„, ๊ฐ‘์ž๊ธฐ ์ •์•กํ• ์ธ์œผ๋กœ ์ •์ฑ…์ด ๋ณ€๊ฒฝ๋œ๋‹ค๋ฉด, ์œ„์˜ ์˜ˆ์ œ์ฒ˜๋Ÿผ ์„œ๋น„์Šค๋ ˆ์ด์–ด์˜ ์–ด๋…ธํ…Œ์ด์…˜๋งŒ ๋ฐ”๊ฟ”์ฃผ๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ณ€๊ฒฝ๋œ ์ •์ฑ…์„ ์ฝ”๋“œ์ƒ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

 

↔ ๋งŒ์•ฝ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„์ฒด๊ฐ€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด?

์ด ํฌ์ŠคํŒ…์„ ์“ฐ๊ฒŒ ๋œ ๊ณ„๊ธฐ๋Š” ๋ณดํ†ต ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ตฌํ˜„์ฒด๊ฐ„์˜ ๊ด€๊ณ„๊ฐ€ 1:N ์ด ์•„๋‹Œ 1: 1 ๊ด€๊ณ„์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ตฌํ˜„์ฒด๊ฐ€ 2๊ฐœ ์ด์ƒ์ด ์•„๋‹ˆ๋ผ๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•„์š”์—†์ง€ ์•Š์„๊นŒ์š”? ๊ตณ์ด ์ธํ„ฐํŽ˜์ด์Šค ์—†์ด ์„œ๋น„์Šค ์ฝ”๋“œ๋งŒ ์กด์žฌํ•ด๋„ ๊ดœ์ฐฎ์ง€ ์•Š์„๊นŒ์š”?

์–ด๋Š์ •๋„๋Š” ๊ทธ๋ ‡๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ, ๊ทธ๋Ÿผ์—๋„ ์—ฌ์ „ํžˆ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตณ์ด ์„ ์–ธํ•˜๊ณ  ๊ตฌํ˜„์ฒด ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด์œ ๋Š” ๊ธฐํš ์ •์ฑ…์— ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์‘ํ•˜๊ณ  ์‹ถ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. "์•„๋ฌด๋ฆฌ ๋ด๋„ ์ด API ๋Š” ๊ธฐํš ์ •์ฑ…์ด ๋ณ€๊ฒฝ๋  ์ผ์ด ์—†์„๊บผ์•ผ" ๋ผ๊ณ  ๋‹จ์–ธํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๊ฒ ์ง€๋งŒ, ์งง์€ ๊ฒฝํ—˜์œผ๋กœ๋‚˜๋งˆ ๊ธฐํš ์ •์ฑ…์€ ์–ผ๋งˆ๋“ ์ง€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋Š๋ผ๊ฒŒ ๋์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์œ„์˜ ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด OCP ๋ฅผ ์ง€ํ‚ฌ ๋•Œ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ํŽธ๋ฆฌํ•จ๊ณผ ์•ˆ์ •์„ฑ ์—ญ์‹œ ๋†“์น  ์ˆ˜ ์—†๋Š” ๋ถ€๋ถ„์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

 

 

 

๋„ค์ด๋ฐ ์ปจ๋ฒค์…˜์€ ์ด๋Œ€๋กœ ๊ดœ์ฐฎ์€๊ฐ€(feat. impl, I)

์ถ”๊ฐ€์ ์œผ๋กœ ๋‹ค๋ฅธ ํฌ์ŠคํŒ…์„ ํ†ตํ•ด ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋„ค์ด๋ฐ ์ปจ๋ฒค์…˜์— ๋Œ€ํ•ด์„œ๋„ ์ƒ๊ฐํ•ด ๋ณผ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

Impl ์„ ๊ตฌํ˜„์ฒด์— ๋ถ™์ด๋Š”๊ฒƒ์ด ๊ด€์Šต์ ์ธ ๋„ค์ด๋ฐ ์ปจ๋ฒค์…˜์ด ๋์ง€๋งŒ ์ด๊ฒƒ์ด ํƒ€๋‹นํ•œ์ง€ ๊ณ ๋ฏผํ•ด๋ณผ ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€ํ‘œ์ ์œผ๋กœ ์ž๋ฐ” Collection ์˜ List ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ArrayList, LinkedList ์—์„œ๋Š” impl ์ด๋ผ๋Š” ์ ‘๋ฏธ์‚ฌ๋Š” ์ฐพ์•„๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์•„๋ž˜๋Š” ์Šคํƒ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ์—์„œ ๋ฐœ์ทŒํ•œ ๊ตฌ๋ฌธ์ž…๋‹ˆ๋‹ค.

Look to the Java standard library itself. Do you see IList, ArrayListImpl, LinkedListImpl? No, you see List and ArrayList, and LinkedList. Here is a nice article about this exact question. Any of these silly prefix/suffix naming conventions all violate the DRY principle as well.

 impl ์„ ์ ‘๋ฏธ์‚ฌ๋กœ ๋ถ™์ด๋Š” ๊ฒƒ์ด DRY ์›์น™์„ ์œ„๋ฐฐํ•˜๋ฉฐ ๋ถˆํ•„์š”ํ•œ ๋„ค์ด๋ฐ ์ปจ๋ฒค์…˜์ด๋ผ๊ณ  ์‹ ๋ž„ํ•˜๊ฒŒ ๋น„ํŒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„ ๊ธ€์„ ์ฝ๊ณ  ๋‚˜๋‹ˆ

์•ž์œผ๋กœ interface ์˜ ๊ตฌํ˜„์ฒด๋ฅผ ๋งŒ๋“ค๋•Œ ๋„ค์ด๋ฐ์„ ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ์ง€ ๋‹ค์‹œ๊ธˆ ์ƒ๊ฐํ•˜๊ฒŒ ๋์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ํšŒ์‚ฌ์˜ ํ”„๋กœ์ ํŠธ๋ถ€ํ„ฐ ์ด๋Ÿฐ์‹์˜ ๋„ค์ด๋ฐ ์ปจ๋ฒค์…˜์„ ๋ฐ”๊พธ๊ณ  ์‹ถ์ง€๋งŒ, ์ด๋ฏธ ๊ด€์Šต์œผ๋กœ ๊ตณ์–ด์ง„ ์‚ฌํ•ญ์„ ๊ฐœ์ธ์ด ๋ฐ”๊พธ๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์†Œ ๋ฌด๋ฆฌ๊ฐ€ ์žˆ๋‹ค๊ณ  ๋ด…๋‹ˆ๋‹ค. ์•ž์œผ๋กœ์˜ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ๋ถ€ํ„ด ์ด๋Ÿฐ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์ธ์ง€ํ•˜๋ฉด์„œ ๋„ค์ด๋ฐ์„ ์‹ ๊ฒฝ์จ์•ผ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

reference

https://see-one.tistory.com/1

https://stackoverflow.com/questions/2814805/java-interfaces-implementation-naming-convention