[자바] java 캡슐화, 싱글톤,this
11. 캡슐화 (encapsulation)
정보 은닉을 활용한 캡슐화
꼭 필요한 정보와 기능만 외부에 오픈함
대부분의 멤버 변수와 메서드를 감추고 외부에 통합된 인터페이스만은 제공하여 일관된 기능을 구현 하게 함
각각의 메서드나 멤버 변수를 접근함으로써 발생하는 오류를 최소화 한다. 정보은닉에서 좀 더 추상화 해서 외부에서 꼭 필요한거 한두개만 오픈하고 나머지는 자동으로 생성하게.
레포트 만들기 예제
public class MakeReport {
StringBuffer buffer = new StringBuffer();
private String line = "===========================================\n";
private String title = " 이름\t 주소 \t\t 전화번호 \n";
private void makeHeader()
{
buffer.append(line);
buffer.append(title);
buffer.append(line);
}
private void generateBody()
{
buffer.append("James \t");
buffer.append("Seoul Korea \t");
buffer.append("010-2222-3333\n");
buffer.append("Tomas \t");
buffer.append("NewYork US \t");
buffer.append("010-7777-0987\n");
}
private void makeFooter()
{
buffer.append(line);
}
public String getReport()
{
makeHeader();
generateBody();
makeFooter();
return buffer.toString();
}
}
public class TestReprt {
public static void main(String[] args) {
MakeReport report = new MakeReport();
String builder = report.getReport();
System.out.println(builder);
}
}
12. 객체 자신을 가리키는 this
this가 하는 일
인스턴스 자신의 메모리를 가리킴
생성자에서 또 다른 생성자를 호출 할때 사용
자신의 주소(참조값)을 반환 함
생성된 인스턴스 메모리의 주소를 가짐
- 클래스 내에서 참조변수가 가지는 주소 값과 동일 한 주소 값을 가지는 키워드
public void setYear(int year)
{
this.year = year;
}
생성자에서 다른 생성자를 호출 하는 this
클래스에 생성자가 여러 개 인경우, this를 이용하여 생성자에서 다른 생성자를 호출할 수 있음
생성자에서 다른 생성자를 호출하는 경우, 인스턴스의 생성이 완전하지 않은 상태이므로 this() statement 이전에 다른 statement를 쓸 수 없음
public class Person {
String name;
int age;
public Person() {
this("이름없음", 1);
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
자신의 주소를 반환하는 this
public class Person {
String name;
int age;
public Person() {
this("이름없음", 1);
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person getPerson() {
return this;
}
public static void main(String[] args)
{
Person p = new Person();
p.name = "James";
p.age = 37;
Person p2 = p.getPerson();
System.out.println(p);
System.out.println(p2);
}
}
13. 객체 간의 협력 (collabration)
객체 지향 프로그래밍에서의 협력
객체 지향 프로그램에서 객체 간에는 협력이 이루어짐
협력을 위해서는 필요한 메세지를 전송하고 이를 처리하는 기능이 구현되어야 함
매개 변수로 객체가 전달되는 경우가 발생
객체 협력의 예
14. 버스 타고 학교 가는 학생의 과정을 객체 지향 프로그래밍으로 구현해보기
버스와 지하철을 타는 예제 프로그래밍
James와 Tomas는 각각 버스와 지하철을 타고 학교에 갑니다.
James는 5000원을 가지고 있었고, 100번 버스를 타면서 1000원을 지불합니다.
Tomas는 10000원을 가지고 있었고, 초록색 지하철을 타면서 1200원을 지불합니다.
두 학생이 버스와 지하철을 타는 상황을 구현해 봅시다. Student.java ``` public class Student {
String studentName;
int grade;
int money;
public Student(String studentName, int money) {
this.studentName = studentName;
this.money = money;
}
public void takeBus(Bus bus) {
bus.take(1000);
this.money -= 1000;
}
public void takeSubway(Subway subway) {
subway.take(1200);
this.money -= 1200;
}
public void showInfo() {
System.out.println(studentName +"님의 남은 돈은 " + money + "원 입니다");
} } ``` Bus.java ``` public class Bus {
int busNumber;
int passengerCount;
int money;
public Bus(int busNumber) {
this.busNumber = busNumber;
}
public void take(int money) { //승차
this.money += money;
passengerCount++;
}
public void showBusInfo() {
System.out.println(busNumber + "번 버스의 승객은 " + passengerCount + "명 이고, 수입은 " + money + "원 입니다");
} } ```
Subway.java
public class Subway {
int lineNumber;
int passengerCount;
int money;
public Subway(int lineNumber) {
this.lineNumber = lineNumber;
}
public void take(int money) {
this.money += money;
passengerCount++;
}
public void showSubwayInfo() {
System.out.println(lineNumber + "번 지하철의 승객은 " + passengerCount + "명 이고, 수입은 " + money + "원 입니다");
}
}
TakeTransTest.java
public class TakeTransTest {
public static void main(String[] args) {
Student studentJ = new Student("James", 5000);
Student studentT = new Student("Tomas", 10000);
Bus bus100 = new Bus(100);
Subway subwayGreen = new Subway(2);
studentJ.takeBus(bus100);
studentT.takeSubway(subwayGreen);
studentJ.showInfo();
studentT.showInfo();
bus100.showBusInfo();
subwayGreen.showSubwayInfo();
}
}
15. 복습해봅시다 (객체 협력)
다음과 같은 상황을 구현해 봅시다.
앞의 예제에서 Edward는 지각을 해서 택시를 타야 했습니다.
20000원을 가지고 있었는데 10000원을 택시비로 사용했습니다.
택시는 '잘나간다 운수' 회사 택시를 탔습니다.
출력결과
16. 여러 인스턴스에서 고통으로 사용하는 변수를 선언하자 - static 변수
공통으로 사용하는 변수가 필요한 경우
여러 인스턴스가 공유하는 기준 값이 필요한 경우
학생마다 새로운 학번 생성
카드회사에서 카드를 새로 발급할때마다 새로운 카드 번호를 부여
회사에 사원이 입사할때 마다 새로운 사번이 필요한
static 변수 선언과 사용하기
static int serialNum;
인스턴스가 생성될 때 만들어지는 변수가 아닌, 처음 프로그램이 메모리에 로딩될 때 메모리를 할당
클래스 변수, 정적변수라고도 함(vs. 인스턴스 변수)
인스턴스 생성과 상관 없이 사용 가능하므로 클래스 이름으로 직접 참조
Student.serialNum = 100;
static 변수 테스트하기
Employee.java
public class Employee {
public static int serialNum = 1000;
private int employeeId;
private String employeeName;
private String department;
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
EmployeeTest.java
public class EmployeeTest {
public static void main(String[] args) {
Employee employeeLee = new Employee();
employeeLee.setEmployeeName("이순신");
System.out.println(employeeLee.serialNum);
Employee employeeKim = new Employee();
employeeKim.setEmployeeName("김유신");
employeeKim.serialNum++;
System.out.println(employeeLee.serialNum);
System.out.println(employeeKim.serialNum);
}
}
System.out.println(employeeLee.serialNum); 이 부분에서 employeeLee 이부분은 인스턴스 변수인데 serialNum은 이미 메모리에 올라와 있는 상태이므로 Employee.serialNum만 쓰고 나머지 다 지워도 출력 및 사용이 가능하다.
- static 변수는 인스턴스에서 공통으로 사용하는 영역임음 알 수 있음
회사원이 입사할 때마다 새로운 사번 부여하기
Employee.java 생성자 구현
...
public Employee()
{
serialNum++;
employeeId = serialNum;
}
...
EmployeeTest.java
public class EmployeeTest {
public static void main(String[] args) {
Employee employeeLee = new Employee();
employeeLee.setEmployeeName("이순신");
Employee employeeKim = new Employee();
employeeKim.setEmployeeName("김유신");
System.out.println(employeeLee.getEmployeeName() + "," + employeeLee.getEmployeeId());
System.out.println(employeeKim.getEmployeeName() + "," + employeeKim.getEmployeeId());
}
}
static 변수와 메서드는 인스턴스 변수, 메서드가 아니므로 클래스 이름으로 직접 참조
System.out.println(Employee.serialNum);
17. static메서드의 구현과 활용, 변수의 유효 범위
static 메서드 만들기
- serialNum 변수를 private으로 선언하고 getter/setter 구현
Employee.java
private static int serialNum = 1000;
...
public static int getSerialNum() {
return serialNum;
}
public static void setSerialNum(int serialNum) {
Employee.serialNum = serialNum;
}
- 클래스 이름으로 호출 가능 ( 클래스 메서드, 정적 메서드 )
System.out.println(Employee.getSerialNum());
static 메서드(클래스 메서드)에서는 인스턴스 변수를 사용할 수 없다
static 메서드는 인스턴스 생성과 무관하게 클래스 이름으로 호출 될 수 있음
인스턴스 생성 전에 호출 될 수 있으므로 static 메서드 내부에서는 인스턴스 변수를 사용할 수 없음
Employee.java
public static void setSerialNum(int serialNum) {
int i = 0;
employeeName = "Lee"; //오류발생
Employee.serialNum = serialNum;
}
EmployeeTest2.java
public class EmployeeTest2 {
public static void main(String[] args) {
System.out.println(Employee.getSerialNum());
Employee.setSerialNum(1003);
System.out.println(Employee.getSerialNum());
}
}
변수의 유효 범위와 메모리
변수의 유효 범위(scope)와 생성과 소멸(life cycle)은 각 변수의 종류마다 다름
지역변수, 멤버 변수, 클래스 변수는 유효범위와 life cycle, 사용하는 메모리도 다름
static 변수는 프로그램이 메모리에 있는 동안 계속 그 영역을 차지하므로 너무 큰 메모리를 할당하는 것은 좋지 않음
클래스 내부의 여러 메서드에서 사용하는 변수는 멤버 변수로 선언하는 것이 좋음
멤버 변수가 너무 많으면 인스턴스 생성 시 쓸데없는 메모리가 할당됨
상황에 적절하게 변수를 사용해야 함
18. static 응용 - 싱글톤 패턴(singleton pattern)
싱글톤 패턴이란?
프로그램에서 인스턴스가 단 한 개만 생성되어야 하는 경우 사용하는 디자인 패턴
static 변수, 메서드를 활용하여 구현 할 수 있음
싱글톤 패턴으로 회사 객체 구현하기
- 생성자는 private으로 선언
private Company() {}
- 클래스 내부에 유일한 private 인스턴스 생성
private static Company instance = new Company();
외부에서 유일한 인스턴스를 참조할 수 있는 public 메서드 제공 ``` public static Company getInstance() {
if( instance == null) { instance = new Company(); } return instance;
}
CompanyTest.java
public class CompanyTest {
public static void main(String[] args) {
Company company1 = Company.getInstance();
Company company2 = Company.getInstance();
System.out.println(company1);
System.out.println(company2);
//Calendar calendar = Calendar.getInstance();
} } ```
19. 복습해봅시다 (static과 싱클톤 패턴)
설명에 따른 객체를 구현하여 테스트 코드가 실행되도록 구현하기
자동차 공장이 있습니다. 자동차 공장은 유일한 객체이고, 이 공장에서 생산되는 자동차는 제작될 때마다 고유의 번호가 부여됩니다.
자동차 번호가 10001부터 시작되어 자동차가 생산될 때마다 10002, 10003 이렇게 번호가 붙도록 자동차 공장 클래스, 자동차 클래스를 구현하세요
다음 CarFactoryTest.java 테스트 코드가 수행 되도록 합니다.
CarFactoryTest.java
public class CarFactoryTest {
public static void main(String[] args) {
CarFactory factory = CarFactory.getInstance();
Car mySonata = factory.createCar();
Car yourSonata = factory.createCar();
System.out.println(mySonata.getCarNum()); //10001 출력
System.out.println(yourSonata.getCarNum()); //10002 출력
}
}