객체지향 프로그래밍 (OOP), Encapsulation

Wonkyun Jung·2023년 2월 15일
0

자바기초

목록 보기
3/4
post-thumbnail

1. 접근제한자와 Encapsulation

제한자(modifier)

  • 클래스,변수,메서드 선언부에 함께 사용되어 부가적인 의미 부여

  • 접근 제한자: public, protected,(default = package),private

  • 그 외 제한자: static, final, abstract, synchronized

    → final : 마지막, 더 이상 바뀔 수 없음 
    
    용도
    
    - **final class - 상속 금지 → 오버라이드 방지**
    - **final method - 더 이상  재정의 할 수 없음: overriding 금지**
    - **final variable - 더 이상 값을 바꿀 수 없음: 상수화**

    **접근 제한자(Access modifier)**
  • 멤버 등에 사용되며 해당 요소를 외부에서 사용할 수 있는지 설정

예제 코드

접근 제한자는 부모의 제한자 범위와 같거나 넓은 범위로만 사용 가능하다

class Parent{
	protected void method() {}
}

public class OverrideRule extends Parent{
	
	@Override
	void method() {}	 //접근 제한자 설정 안 해주면 default -> 에러 (default < protected)
	protected void method() {}
	public void method() {}
	
}



package accessex1;

import accessex2.AccessEx3;
import accessex2.AccessEx4;

public class AccessEx1 extends AccessEx4{
	private int x=10;
	private int y=20;
	
	public static void main(String[] args) {
		AccessEx1 ob1=new AccessEx1();
		System.out.println(ob1.x+"  "+ob1.y);
		System.out.println(ob1.xx+"  "+ob1.yy);
		
		AccessEx2 ob2=new AccessEx2();
		System.out.println(ob2.x+"  "+ob2.y);
		
		AccessEx3 ob3=new AccessEx3();
		System.out.println(ob3.x+"  "+ob3.y);
	}
}

//test1
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The field AccessEx2.x is not visible
The field AccessEx2.y is not visible

//test2
10  20
10000  20000
100  200
1000  2000



AccessEx2.java

//test1
package accessex1;

public class AccessEx2 {
	private int x=100;
	private int y=200;
}

AccessEx2.java

//test2
package accessex1;

public class AccessEx2 {
	int x=100;
	int y=200;

	(default)
}

default가 되므로 protectd, public은 자동

보통 private과 public을 사용하자 protected 는 상속관계만 생각하자

데이터 은닉과 보호 (Encapsulation)

외부에서 변수에 직접 접근하기 때문에 정보를 보호하기 위한 대책이 필요

  • 변수는 private 접근으로 막기
  • 공개되는 메서드를 통한 접근 통로 마련: getter / setter


2. Singleton 디자인 패턴

여러 개의 객체가 필요 없는 경우

  • if 객체를 구별할 필요가 없는 경우 → 수정 가능한 멤버 변수가 없고 기능만 있을 때 (stateless한 객체)
  • 객체를 계속 생성/삭제 하는데 많은 비용이 들어서 재사용이 유리한 경우

Singleton 디자인 패턴

  • 외부에서 생성자 접근 금지 → 생성자의 접근 제한자를 private 으로 설정
  • 내부에서는 private에 접근 가능하므로 직접 객체 생성 → 멤버변수는 private 설정
  • 외부에서 private member에 접근 가능한 getter 생성 → setter는 불필요
  • 객체 없이 외부에서 접근할 수 있도록 getter와 변수에 static 추가
  • 외부에서는 언제나 getter를 통해서 객체를 참조하므로 하나의 객체 재사용

Singleton의 목표: 각각의 객체들이 하나의 메모리 공간에 모아서 관리하자!




예제 코드 1

public class Speaker1 extends Object{
	private int volume;

	public Speaker1() {
		this.volume = 5;
	}

	public int getVolume() {
		return volume;
	}

	public void setVolume(int volume) {
		this.volume = volume;
	}

//	@Override
//	public String toString() {
//		return "볼륨: " + volume;
//	}
}
//일반 객체
public class Main1 {
	public static void main(String[] args) {
		Speaker1 s1=new Speaker1();
		Speaker1 s2=new Speaker1();
		Speaker1 s3=new Speaker1();
		
		System.out.println(s1); //or s1.toString()
		System.out.println(s2);
		System.out.println(s3);

		s1.setVolume(10);
		System.out.println(s1.getVolume());
		System.out.println(s2.getVolume());
		System.out.println(s3.getVolume());
		
		s2.setVolume(20);
		System.out.println(s1.getVolume());
		System.out.println(s2.getVolume());
		System.out.println(s3.getVolume());
	}
}

1번 케이스에서 s1과 s2와 s3는 각각 다른 객체이므로 다른 주소값을 가지고 있다 → Singleton x

예제 코드 2

public class Speaker2 {
	//자기 자신의 클래스 객체 private static 선언 
	//클래스 객체 하나가지고 다 돌려막기 할 거니까
	private static Speaker2 speaker;
	private int volume;
	
  //생성자를 private걸어서 외부에서 바로 생성 못하도록
	private Speaker2() {
		volume=5;
	}

  //Singleton 방식에서 객체 초기화 하는 방법 
	public static Speaker2 getInstance() {
		//자기 자신의 객체가 없으면 새로 생성
		if(speaker==null) {
			speaker=new Speaker2();//여기서 객체 생성
		}
		//자신의 객체가 있다면 자신의 객체 반환
		return speaker;
	}

	public int getVolume() {
		return volume;
	}

	public void setVolume(int volume) {
		this.volume = volume;
	}
}
public class Main2 {
	public static void main(String[] args) {
		Speaker2 s1 = Speaker2.getInstance();
		Speaker2 s2 = Speaker2.getInstance();
		Speaker2 s3 = Speaker2.getInstance();
		
		System.out.println(s1);
		System.out.println(s2);
		System.out.println(s3);
		
		System.out.println(s1.getVolume());
		System.out.println(s2.getVolume());
		System.out.println(s2.getVolume());
		
		s1.setVolume(10);
		System.out.println(s1.getVolume());
		System.out.println(s2.getVolume());
		System.out.println(s3.getVolume());
		
		s2.setVolume(20);
		System.out.println(s1.getVolume());
		System.out.println(s2.getVolume());
		System.out.println(s3.getVolume());
	}
}

2번 case 에서 s1,s2,s3 는 모두 하나의 객체 주소를 가지고 있다. static으로 main 실행전에 메서드 영역에 올라와 있음

예제 코드 3번

public class Speaker3 {
	private  static Speaker3 speaker=new Speaker3();
	private int volume;
	
	private Speaker3() {
		volume=5;
	}

	public static Speaker3 getInstance() {
		return speaker;
	}

	public int getVolume() {
		return volume;
	}

	public void setVolume(int volume) {
		this.volume = volume;
	}
}
public class Main3 {
	public static void main(String[] args) {
		Speaker3 s1 = Speaker3.getInstance();
		Speaker3 s2 = Speaker3.getInstance();
		Speaker3 s3 = Speaker3.getInstance();
		
		System.out.println(s1);
		System.out.println(s2);
		System.out.println(s3);
		
		System.out.println(s1.getVolume());
		System.out.println(s2.getVolume());
		System.out.println(s2.getVolume());
		
		s1.setVolume(10);
		System.out.println(s1.getVolume());
		System.out.println(s2.getVolume());
		System.out.println(s3.getVolume());
		
		s2.setVolume(20);
		System.out.println(s1.getVolume());
		System.out.println(s2.getVolume());
		System.out.println(s3.getVolume());
	}

2번과 내용은 동일하다

0개의 댓글