추상화(Abstraction)

Joy🌱·2022년 12월 29일
0

☕ Java

목록 보기
16/40
post-thumbnail

💁‍♀️ 추상화(Abstraction)란,
공통된 부분을 추출하고 공통되지 않은 부분은 제거한다는 의미를 가지며, 추상화의 목적은 유연성을 확보하기 위함
유연성 확보는 여러 곳에 적용 될 수 있는 유연한 객체를 의미하며, 즉 재사용성이 높아질 수 있게 한다는 의미
객체의 재사용성이 증가하면 중복 작성되는 코드를 줄일 수 있으며, 오류 발생 가능성을 감소시키고 유지보수성을 증가


🙋‍ 잠깐 ! 왜 추상화를 해야하나요?
추상화의 목적은 유연성을 확보하기 위함.
유연성 확보는 여러 곳에 적용 될 수 있는 유연한 객체를 의미하며, 즉 재사용성이 높아질 수 있게 한다는 의미
객체의 재사용성이 증가하면 중복 작성되는 코드를 줄일 수 있으며, 오류 발생 가능성을 감소시키고 결과적으로 유지보수성을 증가시킴


👀 카레이서가 자동차를 운전하는 프로그램을 추상화

◼ Car Class

public class Car {
	
	>>> 시동을 켜거나 끄거나, 앞으로 가거나 멈추거나 하는 행동은 시동이 걸려있는지의 상태를 확인해야함
	>>>, 메소드간에 서로 공유해야 하는 속성이 존재. 그 속성을 필드에 작성
	private boolean isOn;	>>> 초기에는 시동이 꺼진 false 상태 (기본값)
	private int speed;		>>> 초기에는 속도 0
	
	public void startUp() {
		// 시동 걸기 - 시동이 걸려있는 상태인 경우에는 할 일이 없고, 
        // 시동이 걸려있지 않은 경우에만 시동을 검
		if(isOn) {
			System.out.println("이미 시동이 걸려있습니다.");
		} else {
			isOn = true;
			System.out.println("시동을 걸었습니다. 이제 출발할 준비가 완료 되었습니다.");
		}
	}
	
	public void go() {
		if(isOn) {
			// 가속을 할 때마다 속도를 10km/h씩 증가
			System.out.println("차가 앞으로 움직입니다.");
			speed += 10;
			System.out.println("현재 차의 시속은 " + speed + "km/h 입니다.");
		} else {
			System.out.println("차의 시동이 걸려있지 않았습니다. 시동을 먼저 걸어주세요.");
		}
	}
	
	public void stop() {
		if(isOn) {
			if(speed > 0) {
				speed = 0;
				System.out.println("브레이크를 밟았습니다. 차를 멈춥니다.");
			} else {
				System.out.println("차는 이미 멈춰있는 상태입니다.");
			}
		} else {
			System.out.println("차의 시동이 걸려있지 않았습니다. 시동을 먼저 걸어주세요.");
		}
	}
	
	public void turnOff() {
		if(isOn) {
			if(speed > 0) {
				System.out.println("달리는 상태에서 시동을 끌 수 없습니다. 차를 우선 멈춰주세요.");
			} else {
				isOn = false;
				System.out.println("시동을 끕니다. 다시 운행하시려면 시동을 켜주세요.");
			}
		} else {
			System.out.println("이미 시동이 꺼져있는 상태입니다. 시동 상태를 확인해주세요.");
		}
	}
}

◼ CarRacer Class

package com.greedy.section03.abstraction;

public class CarRacer {
	
	>>> CarRacer가 상호 작용할 Car 클래스를 CarRacer는 알고 있어야 함
	>>> 알고 있다는 의미는 필드에 가지고 있다는 의미
    
	private Car car = new Car(); // CarRacer 클래스는 Car 클래스의 car필드를 알고 있다. => Car 클래스의 메소드를 호출할 수 있다.
	
	public void startUp() {
		car.startUp();
	}
	
	public void stepAccelator() {
		car.go();
	}
	
	public void stepBreak() {
		car.stop();
	}
	
	public void turnOff() {
		car.turnOff();
	}
}

◼ Application Class

public class Application {
	
	public static void main(String[] args) {
	
		// 기능을 최대한 단순화 시켜서 프로그램을 만들기
		// 1. 자동차는 처음에 멈춘 상태로 대기
		// 2. 카레이서는 먼저 자동차에 시동 걸기. 이미 걸려있는 경우 다시 시동을 걸 수 없음
		// 3. 카레이서가 엑셀을 밟으면 시동이 걸린 상태일 경우 자동차는 시속 10km/h 증가하며 앞으로 나감
		// 4. 자동차가 달리는 중인 경우 브레이크를 밟으면 자동차의 시속은 0으로 떨어지며 멈춤
		// 5. 브레이크를 밟을 때 자동차가 달리는 중이 아니라면 이미 멈춰있는 상태라고 안내
		// 6. 카레이서가 시동을 끄면 더 이상 자동차는 움직이지 않음
		// 7. 자동차가 달리는 중이라면 시동을 끌 수 없음
	
		>>> 여기서 필요한 객체는 카레이서와 자동차 객체
		// 카레이서가 수신할 수 있는 메세지는 카레이서가 할 일과 동일
		// 1. 시동을 걸어라
		// 2. 엑셀을 밟아라
		// 3. 브레이크를 밟아라
		// 4. 시동을 꺼라
		  
		// 자동차가 수신할 수 있는 메세지는 자동차가 해야 할 일과 동일
		// 1. 시동을 걸어라
		// 2. 앞으로 가라
		// 3. 멈춰라
		// 4. 시동을 꺼라
		
		// 카레이서 생성
		CarRacer racer = new CarRacer(); >>> AppCarRacer의 메소드를 이용
		
		// 스캐너로 입력 받은 메뉴에 따라서 카레이서의 행동이 달라짐
		Scanner sc = new Scanner(System.in);
		
		while(true) {
			System.out.println("========== 카레이싱 프로그램 ==========");
			System.out.println("1. 시동 걸기");
			System.out.println("2. 전진");
			System.out.println("3. 정지");
			System.out.println("4. 시동 끄기");
			System.out.println("9. 프로그램 종료");
			System.out.print("메뉴 선택 : ");
			int no = sc.nextInt();
			
			switch(no) {
			case 1 : racer.startUp(); break;
			case 2 : racer.stepAccelator(); break;
			case 3 : racer.stepBreak(); break;
			case 4 : racer.turnOff(); break;
			case 9 : System.out.println("프로그램을 종료합니다."); return;
			default : System.out.println("잘못 된 번호를 선택하셨습니다.");
			}
		}
	}
}

👀 DTO(Data Transfer Object)

캡슐화의 원칙에 일부 어긋나기는 하지만 매번 추상화를 하지않아도 되는 객체도 존재.
행위 위주(Method)가 아닌 데이터를 하나로 뭉치기 위한 객체(Data Transfer object)의 경우, 모든 필드를 private로 직접 접근을 막고, 각 필드 값을 변경하거나 반환하는 메소드를 세트로 작성.
메소드는 설정자(setter값을 설정), 접근자(getter값을 가져옴)들로 구성


  • 설정자(setter) 작성 규칙 (값을 설정)
    • 필드 값을 변경할 목적의 매개변수를 변경하려는 필드와 같은 자료형으로 선언
    • 호출 당시 전달 되는 매개변수의 값을 이용하여 필드의 값을 변경
public void set필드명(매개변수) {
	필드 = 매개변수;
}

  • 접근자(getter) 작성 규칙 (값을 가져옴)
    • 필드의 값을 반환 받을 목적의 메소드 집합을 의미
    • 각 접근자는 하나의 필드에만 접근하도록 함
    • 필드에 접근해서 기록된 값을 return을 이용하여 반환하며, 이 때 반환 타입은 반환하려는 값의 자료형과 일치시킴
public 반환형 get필드명() {
 	return 필드명;
 }

◼ MemberDTO Class

public class MemberDTO {

	// 취급하려고 하는 회원 정보를 구상해서 필드를 작성
	private int number;
	private String name;
	private int age;
	private double height;
	private boolean isActivated;
	
    // setter
	public void setNumber(int number) {
		this.number = number; >>> this : 전역변수 number 지칭
	} 
	
	public void setName(String name) {
		this.name = name; 
	}
	public void setAge(int age) {
		this.age = age; 
	}
	public void setHeight(double height) {
		this.height = height; 
	}
    >>> boolean의 설정자는 set 필드명에 is를 제외하고 넣는 것이 일반적인 관례
	public void setActivated(boolean isActivated) {
		this.isActivated = isActivated; 
	}
	
	// getter
	public int getNumber() {
		return number; >>> 필드값 number를 반환
	}
	public String getName() {
		return name; 
	}
	public int getAge() {
		return age;
	}
	public double getHeight() {
		return height;
	}
	>>> boolean의 접근자는 get으로 시작하지않고 is로 시작하는 것이 일반적인 관례
	public boolean isActivated() {
		return isActivated;
	}
}

◼ Application Class

public class Application {

	public static void main(String[] args) {
    
		MemberDTO member = new MemberDTO();
        
		member.setNumber(5);
		member.setName("효연이");
		member.setAge(26);
		member.setHeight(158.0);
		member.setActivated(true);
		
		System.out.println("회원번호 : " + member.getNumber());
		System.out.println("회원명 : " + member.getName());
		System.out.println("나이 : " + member.getAge());
		System.out.println("키 : " + member.getHeight());
		System.out.println("활성화 상태 : " + member.isActivated());
	}
}

📌 Ref.

* 캡슐화 원칙에 따라 작성했지만 실제로는 캡슐화가 의미없을 정도로 필드명을 그대로 사용한 설정자와 접근자로 인해 
  캡슐화 효과가 없음. 하지만 데이터를 주로 다루는 객체의 경우 행위를 추상화 하지않고, 
  미리 모든 필드에 접근 가능성을 염두에 두고 작성해두는 관례로 인해 현재도 많이 사용되고 있음
profile
Tiny little habits make me

0개의 댓글

관련 채용 정보