OOP(Object Oriented Programming) 객체 지향 프로그래밍

서이·2022년 2월 11일
0

Java

목록 보기
3/27

OOP는 객체를 기준으로 코드를 나누어 구현한다. 자바의 경우 그 구성 부분 단위가 클래스이다. 자세히 말하면 클래스는 설계도고 구현체는 인스턴스이다.
OOP는 객체들의 유기적인 관계를 통해서 프로세스가 진행된다.

특징을 살펴보도록 하자.

캡슐화, 정보은닉, 추상화, 다형성


캡슐화(Encapsulation)

· 하나의 객체에 대해 그 객체가 특정한 목적을 위한 필요한 변수나 메소드를 하나로 묶는 것을 의미한다, 캡슐화는 중요한 데이터를 쉽게 바꾸지 못하도록 할 때 사용한다.
· 따라서 클래스를 우리가 만들 때 훗날 이 클래스에서 만들어진 객체가 특정한 목적을 잘 수행할 수 있도록 사용해야할 변수와 그 변수를 가지고 특정한 액션 즉 메서드를 관련성 있게 클래스에 구성해야한다.


정보 은닉을 활용한 캡슐화

· 꼭 필요한 정보와 기능만 외부에 오픈함
(캡슐화를 하는 중요한 목적은 바로 정보은닉이다, 캡슐화는 접근제어자를 통해 이루어진다. 유저 정보를 가지고 있는 user라는 객체에서 유저의 정보가 public으로 선언되어 있다면, 누구든 접근해서 유저 정보를 변경할 수 있다. 그렇기 때문에 private로 해서 데이터를 보호해서 접근을 제한해야한다. 또한 pprivate으로 제어한 멤버 변수도 public 메서드가 제공되면 접근 가능하지만 public으로 공개되었을 때보다 private 일때 각 변수에 대한 제한을 public 메서드에서 제어할 수 있다.

)

· 대부분의 멤버 변수와 메서드를 감추고 외부에 통합된 인터페이스만은 제공하여   일관된 기능을 구현 하게 함

· 각각의 메서드나 멤버 변수를 접근함으로써 발생하는 오류를 최소화 한다.



접근 제어 지시자(access modifier)와 정보은닉(infomation hiding)
↳ 클래스 외부에서 클래스의 멤버 변수, 메서드, 생성자를 사용할 수 있는지 여부를 지정하는 키워드 (정보은닉 보다는 정보를 보호한다는 의미로 알아두기)

· private : 같은 클래스 내부에서만 접근 가능(외부 클래스, 상속 관계의 클래스에서도 접근 불가)
· 아무것도 없음(default) : 같은 패키지 내부에서만 접근 가능(상속 관계라도 패키지가 다르면 접근 불가)
· protected : 같은 패키지나 상속관계의 클래스에서 접근 가능하고 그 외 외부에서는 접근 할 수 없음
· public : 클래스의 외부 어디서나 접근 할 수 있음


get()/ set() 메서드
· private 으로 선언된 멤버 변수(필드)에 대해 접근, 수정할 수 있는 메서드를 public으로 제공
· get() 메서드만 제공 되는 경우 read-only 필드


public class BirthDay {
	
	private int day;
	private int month;
	private int year;
	
	private boolean isValid;
	
	/*멤버변수는 초기화를 하지 않아도 변수의 타입에 맞는 기본ㄴ값으로 초기화됨(int day 
	 -> 0 , boolean은 false*/
	
	public int getDay() {
		return day;
	}
	
	public void setDay(int day) {
		this.day = day;
	}
	/*클래스 내 참조변수가 가지는 주소값과 동일한 주소 값을 가지는 키워드
	 -> 생성된 인스턴스 메모리의 주소를 가짐*/
	
	public int getMonth() {
		return month;
	}

	public void setMonth(int month) {
		if( month < 1 || month > 12) {
			isValid = false;
		}
		else {
			isValid = true;
			this.month = month;
		}
		
	}

	public int getYear() {
		return year;
	}

	public void setYear(int year) {
		this.year = year;
	}
	public void showDate() {
		if(isValid) {
			System.out.println( year + "년 " + month + "월 " + day + "일 입니다.");
		}
		else {
			System.out.println("유효하지 않은 날짜입니다.");
		}
	}
	
	public boolean getIsValid() {
		return isValid;
	}
	
}


public class BirthDayTest {

	public static void main(String[] args) {

		BirthDay date = new BirthDay();
		date.setYear(2022);
		date.setMonth(12);
		date.setDay(30);
		
		/*private 을 안하면 직접 date.month = 100; 라고 지정할 수 없음
		멤버변수의 오류를 , 객체를 잘못 사용되는것을 노출하게 되고 문제가 생길 수 있음*/
		
		1/*모든 정보를 private 하는 것은 아님*/
		
		date.showDate();
	}

}

다형성(Polymorphism)

OOP에서 다형성의 개념을 녹여내는 방법은 두가지인데. 바로 오버라이딩(Overriding)과 오버로딩(Overloading)이다.
다형성은 상속을 통해 기능을 확장하거나 변경하는 것을 가능하게 해준다. 즉, 다형성은 형태가 같은데 다른 기능을 하는 것을 의미한다.(같은 동작이지만 다른 결과물이 나올 때 다형이라고 생각하면 된다) 이를 통해 코드의 재사용, 코드 길이 감소가 되어 유지보수가 용이하도록 도와준다.(단일상속만 가능)


ex) 포유류 클래스에 여러 속성들을 정의해놓고 포유류에 해당하는 종, 예를 들면 강아지 클래스가 필요한 경우 포유류 클래스와 상속 관계를 맺는다. 상속 관계를 맺으면 자식 객체를 생성할 때 부모 클래스의 속성들을 자동으로 물려받기 때문에 자식 클래스에서 또 정의할 필요가 없다. 이것이 상속이 필요한 이유이다.


오버로딩(Overloading)
-같은 이름의 메서드를 사용하지만 메서드마다 다른 용도로 사용되며 그 결과물도 다르게 구현할 수 있게 만드는 개념이며 가능하게 하려면 메서드끼리 이름은 같지만 매개변수의 갯수나 데이터 타입이 다르면 오버로딩이 적용된다.

public class Animal {
	
	void cat() {
		System.out.println("하나는 8살입니다.");
	}
	
	void cat(String a,int b) {
		System.out.println(a + "는 " + b + "살입니다.");
	}
	
	void cat(String c) {
		System.out.println(c + "는 8살입니다.");
	}



	
	public static void main(String[] args) {
		Animal animal = new Animal();
		animal.cat();
		animal.cat("두리", 8);
		animal.cat("서이");
	}
}

                                         ↓


오버라이딩(Overriding)
-부모 클래스를 상속받은 자식 클래스에서 부모클래스에서 만들어진 메서드를 자식 클래스에서 자신의 입맛대로 다시 재정의해서 사용하는 것을 말한다.

	class Woman{ //부모클래스
	    public String name;
	    public int age;
	    
	    //info 메서드
	    public void info(){
	        System.out.println("여자의 이름은 "+name+", 나이는 "+age+"살입니다.");
	    }
	    
	}
	 
	class Job extends Woman{ //Woman클래스(부모클래스)를 상속받음 : 
	 
	    String job;
	    
	    public void info() {//부모(Woman)클래스에 있는 info()메서드를 재정의
	        super.info(); //super예약어를 사용하는 이유는 자식클래스에서 
           //재정의된 info() 메서드에 의해 부모클래스에 있는 info()메서드가 
           //가려지기(덮어썼기) 때문이다.
	        System.out.println("여자의 직업은 "+job+"입니다.");
	    }
	}
	//파일 명과 main(String[] args)가 들어가는 클래스의 이름이 일치해야함!!
	//기존 파일명 : Woman >> Woman_1로 변경하고 아래 클래스 명을 
   //OverTest >> Woman_1로 변경하였음! 
	public class Woman_1 {
	    public static void main(String[] args) {
	        
	        //Job 객체 생성
	        Job job = new Job();
	        
	        //변수 설정
	        job.name = "유리";
	        job.age = 30;
	        job.job = "프로그래머";
	        
	        //호출
	        job.info();
	        
	    }
	 
	}

추상 클래스(abstract class)

· 구현 코드 없이 메서드의 선언만 있는 추상 메서드(abstract method)를 포함한 클래스
· 메서드 선언(declaaration) : 반환타입, 메서드 이름, 매개변수로 구성
· 메서드 정의(definition) : 메서드 구현(implementation)과 동일한 의미 구현부(body)를 가짐({})
     ex) int add(int x, int y); // 선언
            int add(int x, int y){} // 구현부가 있음, 추상 메서드 아님
· 목적 : 부모 클래스에서 구체화하여 정의할 필요가 없을 경우, 추상메서드로 선언만하고 상속받은 자식   클래스에서 재정의하도록 할 때 사용
· abstract 예약어를 사용
· 추상 클래스는 new 할 수 없음(인스턴스화 할 수 없음,구현이 되지않은 불완전한 메서드이므로)

 

추상 클래스 구현하기

· 메서드에 구현 코드가 없으면 abstract로 선언
· abstract로 선언된 메서드를 가진 클래스는 abstract로 선언
· 모든 메서드가 구현 된 클래스라도 abstract로 선언되면 추상 클래스로 인스턴스화 할 수 없음
· 추상 클래스의 추상 메서드는 하위 클래스가 상속하여 구현
· 추상 클래스 내의 추상 메서드 : 하위 클래스가 구현해야하는 메서드
· 추상 클래스 내의 구현 된 메서드 : 하위 클래스가 공통으로 사용하는 메서드(필요에 따라 하위 클래스에서 재정의 함)

public abstract class Computer {
	
	public abstract void display();
	public abstract void typing();
	
	public void turnOn() {
		
		System.out.println("전원을 켭니다");
	}
	
	void turnOff() {
		System.out.println("전원을 끕니다");
	}
}



public class Desktop extends Computer{

	@Override
	public void display() {
		System.out.println("Desktop display");
		
	}

	@Override
	public void typing() {
		System.out.println("Desktop typing");
		
	}

	@Override
	void turnOff() {
		System.out.println("Desktop turnOff");
	}
	
}



public abstract class NoteBook extends Computer{

	@Override
	public void display() {
	System.out.println("NoteBook display");
	}
}



public class MyNoteBook extends NoteBook{
  @Override
  public void typing() {
	  System.out.println("MyNoteBook typing");
  }
}



public class ComputerTest {

	public static void main(String[] args) {
		
		Computer desktop = new Desktop(); // 상위클래스 Computer 타입으로 쓸 수 있음 
        //상속에서 업캐스팅은 묵시적으로 가능하다. 단, 여기서 desktop의 변수로 사용할 수 
        //있는 것은 Computer에 정의된 display,typing,turnOn,turnOff 만약 desktop에 
        //추가적으로 구현한 메서드가 있으면 그건 구현할 수 없음.
		desktop.display();
		//추상클래스는 상속을 하기위해 만들어짐
		//구현코드가 있는 애들은 하위에서 공통으로 쓸 애들은 상위클래스에서 구현, 
        //하위클래스에서 구체적으로 구현 할 애들은 추상클래스 상태로 나둠, 그게 아니라 
        //다 구현을 했음에도 추상클래스로 둘 경우에는 상속만을 위해서 쓰는 클래스임
		//여러가지 기능들을 구현했지만 인스턴스화 할게 아니라 상속만을 하기위한 클래스이다.
	}

}


추상클래스의 응용 - 템플릿 메서드 패턴

·추상 메서드나 구현 된 메서드를 활용하여 코드의 흐름(시나리오)를 정의하는 메서드

·final로 선언하여 하위 클래스에서 재정의 할 수 없게 함
final 변수 : 값이 변경될 수없는 상수
final 메서드 : 하위 클랫에서 재정의 할 수 없는 메서드
final 클래스 : 상속할 수 없는 클래스

·프레임워크에서 많이 사용되는 설계 패턴

·추상 클래스로 선언된 상위 클래스에서 템플릿 메서드를 활용하여 전체적인 흐름을 정의 하고 하위 클래스에서

·다르게 구현되어야 하는 부분은 추상 메서드로 선언하여 하위 클래스에서 구현 하도록 함



public abstract class Car {
	
	public abstract void drive();
	public abstract void stop();
	public abstract void wiper();
	public void startCar() {
		System.out.println("시동을 켭니다");
	}
	public void turnOff() {
		System.out.println("시동을 끕니다");
	}
	
	public void washCar() {} //필요에 의해서 씀(구현부가 없음)
	
	final public void run() {
		startCar();
		drive();
		wiper();
		stop();
		turnOff();
		washCar();
	}
}



public class AICar extends Car {

	@Override
	public void drive() {
		 System.out.println("자율 주행 합니다");
		 System.out.println("자동차가 스스로 방향을 바꿉니다.");
	}

	@Override
	public void stop() {
		System.out.println("장애물 앞에서 스스로 멈춥니다");
		
	}

	@Override
	public void wiper() {
		// TODO Auto-generated method stub
		
	}
	
	@Override
	public void washCar() {
		System.out.println("자동 세차를 합니다.");
	}
}



public class ManualCar extends Car{

	@Override
	public void drive() {
		System.out.println("사람이 운전합니다.");
		System.out.println("사람이 핸들을 조작합니다.");
		
	}

	@Override
	public void stop() {
		System.out.println("장애물 앞에서 브레이크를 밟아서 정지합니다.");
		
	}

	@Override
	public void wiper() {
		// TODO Auto-generated method stub
		
	}
}



public class CarTest {

	public static void main(String[] args) {
		
		Car aiCar = new AICar();
		aiCar.run();
		
		System.out.println("=====================");
		Car mCar = new ManualCar();
		mCar.run();

	}
}

여러 자바 파일에서 사용하는 상수 값 정의

Define.java

public class Define {

	public static final int MIN = 1;
	public static final int MAX = 999999;
	public static final double PI = 3.14;
	public static final String GREETING = "Good Morning!";
	public static final int MATH_CODE = 1001;
	public static final int CHEMISTRY_CODE = 1002;
	
}


UsingDefine.java

public class UsingDefine {

	public static void main(String[] args) {

		System.out.println(Define.GREETING);
		System.out.println(Define.MIN);
		System.out.println(Define.MAX);
		System.out.println(Define.MATH_CODE);
		System.out.println(Define.CHEMISTRY_CODE);
		System.out.println("원주률은" + Define.PI + "입니다.");
	}

}

인터페이스(Interface)

· 모든 메서드가 추상 메서드로 선언됨 public abstract
· 모든 변수는 상수로 선언됨 public static final

Calc.java

public interface Calc {

	double PI = 3.14;
	int ERROR = -99999999;
	
	int add(int num1, int num2);
	int substract(int num1, int num2);
	int times(int num1, int num2);
	int divide(int num1, int num2);
	
}


Calculator.java

public abstract class Calculator implements Calc{

	@Override
	public int add(int num1, int num2) {
		return num1 + num2;
	}

	@Override
	public int substract(int num1, int num2) {
		return num1 - num2;
	}
}


CompleteCalc.java

public class CompleteCalc extends Calculator{
	
	@Override
	public int times(int num1, int num2) {
		return num1 * num2;
	}

	@Override
	public int divide(int num1, int num2) {
		if( num2 == 0 )
			return ERROR;
		else 
			return num1 / num2;
	}
	
	public void showInfo() {
		System.out.println("모두 구현하였습니다.");
	}
}


CalculatorTest.java

public class CalculatorTest {

	public static void main(String[] args) {
		Calc calc = new CompleteCalc();
		int num1 = 10;
		int num2 = 2;
		
		System.out.println(num1 + "+" + num2 + "=" + calc.add(num1, num2));
		System.out.println(num1 + "-" + num2 + "=" +calc.substract(num1, num2));
		System.out.println(num1 + "*" + num2 + "=" +calc.times(num1, num2));
		System.out.println(num1 + "/" + num2 + "=" +calc.divide(num1, num2));
	}
}

인터페이스 구현과 형 변환

인터페이스를 구현한 클래스는 인터페이스 형으로 선언한 변수로 형 변환 할 수 있음

Calc calc = new CompleteCalc();

상속에서의 형 변환과 동일한 의미

클래스 상속과 달리 구현 코드가 없으므로 여러 인터페이스를 구현할 수 있음
(추상클래스는 단일상속, 인터페이스는 다중상속)

형 변환되는 경우 인터페이스

인터페이스가 하는 일

· 클래스나 프로그램이 제공하는 기능을 명시적으로 선언
· 일종의 클라이언트 코드와의 약속이며 클래스나 프로그램이 제공하는 명세(specification)
· 클라이언트 프로그램은 인터페이스에 선언된 메서드 명서만 보고 이를 구현한 클래스를
  사용할 수 있음
· 어떤 객체가 하나의 인터페이스 타입이라는 것은 그 인터페이스가 제공하는 모든 메서드를 구현했다는 의미임
· 인터페이스를 구현한 다양한 객체를 사용함 - 다형성 ex) JDBC 인터페이스

인터페이스를 활용한 다형성 구현 (dao 구현하기)

profile
작성자 개인이 잊을 때마다 보라고 정리한 글

0개의 댓글

관련 채용 정보