본문 바로가기
객체 지향 프로그래밍 입문

[객체 지향 프로그래밍 입문] 캡슐화

by 코딩하는경준 2022. 4. 16.

캡슐화란

  • 데이터 + 관련 기능 묶기
  • 객체가 기능을 어떻게 구현했는지 외부에 감추는 것
  • 정보 은닉(Information Hiding) 의미 포함
  • 외부에 영향 없이 객체 내부 구현 변경 가능

캡슐화를 하지않았을때

사용자의 정보를 가지고있는 Account

package com.example.cap.domain;

import com.example.cap.enumType.Grade;
import lombok.*;

import javax.persistence.*;
import java.time.LocalDate;

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Setter
@Getter
@Entity
public class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private int age;
    private LocalDate createAt;

    @Enumerated(EnumType.STRING)
    private Grade grade;
}

Account 의 등급을 담은 Enum

package com.example.cap.enumType;

public enum Grade {

    VIP,BASIC
}

데이터베이스에 접근할 수 있는 AccountRepository

package com.example.cap.repository;

import com.example.cap.domain.Account;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AccountRepository extends JpaRepository<Account,Long> {
}

비즈니스 로직이 수행되는 AccountService

package com.example.cap.service;

import com.example.cap.domain.Account;
import com.example.cap.enumType.Grade;
import com.example.cap.repository.AccountRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

@RequiredArgsConstructor
@Service
public class AccountService {

    private final AccountRepository accountRepository;

    @Transactional
    public void updateGrade(Long id){
        Account account = accountRepository.findById(id).get();

        if(account.getAge() >= 19) { // 만약 19세 이상일 경우
            account.setGrade(Grade.VIP);    // account의 등급을 VIP로 지정
        }
    }
}

위 예시는 account 의 나이가 19 세 이상일 경우에 등급을 VIP로 바꾸는 요구사항 입니다.
위와 같은 서비스 로직에는 캡슐화가 적용되지 않았는데요,
캡슐화를 사용하여 더 쉽고 간결하게 표현하며 정보의 은닉성을 표현해보겠습니다.

캡슐화 후

Account 안에 updateGrade() 라는 메소드를 만들어서 나이가 19세 이상일 경우 해당 등급을 VIP로 업데이트 하는 메소드를 만들어줍니다.

package com.example.cap.domain;

import com.example.cap.enumType.Grade;
import lombok.*;

import javax.persistence.*;
import java.time.LocalDate;

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Setter
@Getter
@Entity
public class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private int age;
    private LocalDate createAt;

    @Enumerated(EnumType.STRING)
    private Grade grade;

    public void updateGrade() {
        if(this.getAge() > 19) {
            this.grade = Grade.VIP;
        }
    }
}

전 과는 다르게 account 안에 있는 updateGrade() 메소드를 활용하여 코드를 줄인 모습을 볼 수 있습니다.

package com.example.cap.service;

import com.example.cap.domain.Account;
import com.example.cap.repository.AccountRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

@RequiredArgsConstructor
@Service
public class AccountService {

    private final AccountRepository accountRepository;

    @Transactional
    public void updateGrade(Long id){
        Account account = accountRepository.findById(id).get();

        account.updateGrade(); 
    }
}

캡슐화를 사용해서 얻는 이점

캡슐화를 사용했을때의 이점은 이런 요구사항이 AccountService의 updateGrade 메소드에만
적용되어있던 것이 아닌 다른 곳에어도 적용이 되어있다면,
일일이 찾아서 하나하나씩 고쳐야하는 자원(시간)적 손실이 발생합니다.
이번시간에는 코드의 가독성 증진, 코드의 영향을 최소화시킬 수 있는 캡슐화를 알아봤습니다.

댓글