[Book Review] JAVA의 신 (9)

[Book Review] JAVA의 신 (9)

CH13. Interface, Abstract, Final & Enum

1. Interface

메소드 내용이 없는 interface

interface와 abstract 클래스가 있음.
이것을 이해하기 위해 시스템 절차가 어떻게 되는지 알아야함
어떤 시스템을 개발하든 “방법론”을 사용해야함
방법론 = 시스템을 어떻게 만들 것인지에 대한 절차를 설명하고 어떤 문서(산출물)를 작성해야하는지 정래해놓은 공동 절차

일반적인 절차
(1) 분석
(2) 설계
(3) 개발 및 테스트
(4) 시스템 릴리즈

1) 분석
요구사항 분석 : 시스템을 만들어달라고 한 사람들 (SI에서는 고객, SM에서는 현업, 고객이 없는 회사는 기획)에게 어떻게 개발하기를 원하는지 물어본다

*SI (System Integration) 은행이나 공공기관 등에서 어떤 시스템을 만들려고 할 때 
회사에 있는 개발자만으로 시스템을 개발하기 어렵고 비용도 많이 들기 때문에 일정 기간동안 시스템을 만들어주는 것
-----------------------------------------------------------------
*SM (System Maintenance) : 시스템을 운영하고 유지 보수하는 것 / 
만들어져있는 것을 그대로 쓰는 것이 아니라 보완하고 발전시켜 나가기 때문에 
SM에서도 운영하는 작업만 수행하는 것이 아니라 개발 작업도 병행

2) 설계
분석 단계에서 만든 대략적인 그림을 프로그램으로 만들 수 있도록 설계하는 작업 수행 / 어떤 메소드를 쓸 것인지 데이터는 어떻게 저장할지 등의 세부적인 것들을 정리

3) 개발 및 테스트
설계에서 만들기로 한 것들을 개발하는 단계. 실제 시스템에서 제공해야하는 기능들을 이때 만듦. 제대로 동작하는지 테스트까지

4) 시스템 릴리즈
시스템을 사용자에게 제공하는 단계, 시스템을 오픈한 이후에는 운영/유지보수 거치며 문제 수정

설계 단계에서 프로그램을 어떻게 만들 것인지 정리하는데 이 때 워드/엑셀로 문서만 만드는게 아니라 어떤 클래스를 만들지, 어떤 메소드를 만들지, 어떤 변수를 만들지를 정리하는 작업도 같이한다.

내용들을 문서에만 정리하면 나중에 메소드 관련 내용들 변경되면 문서도 수정해야해서 2중3중 고생

-> 그래서 이 설계 단계에서 인터페이스라는 것을 만들어 두면 개발할 때 메소드의 이름/매개변수 등을 고민하지 않아도 됨.

-> 개발자의 역량 따라 메소드 이름과 매개변수 다를 수 있는데 이것 또한 격차 줄일 수 있음

인터페이스에는 다음과 같은 메소드 선언되어있음

public boolean equals(Object o);

매개변수로 넘어온 객체와 현재 객체가 같은지 boolean으로 리턴하는 역할

“인터페이스가 구현된 클래스”가 어떻게 되어있는지 알아야하나?
= 내부 구현 별로 안중요하고 원하는 메소드 호출하고 그 답만 받으면됨

가장 일반적인 것이 DAO (Data Access Object 패턴) 데이터를 저장하는 저장소에서 원하는 값을 요청하고 응답을 받음

ex)
어느 학원의 회원정보를 확인하는 MemberDAO 인터페이스 만든다고 했을 때 어떤 메소드들이 필요할까?

  • 회원 전화번호를 매개변수로 넘겨주면 회원의 상세정보 제공
  • 이름을 넘겨주면 동명이인 포함 정보들의 목록 보여줌
    해당 인터페이스를 구현해서 DBMS를 통해 작성한 메소드에서 결과만 제대로 넘겨주면 됨.
    이렇게 인터페이스를 정해두면 (선언 / 구현) 구분가능

정리

  • 설계시 선언해두면 개발할 때 기능을 구현하는 데에만 집중할 수 있다
  • 개발자의 역량에 따른 메소드의 이름과 매개변수 선언의 격차를 줄일 수 있다
  • 공통적인 인터페이스와 abstract 클래스를 선언해 놓으면 선언과 구현을 구분할 수 있다

인터페이스 만들기
앞의 MemberDTO 관리하는 MemberManagerImpl이라는 클래스 만들어야함
어떤 메소드들이 있어야하는지를 정의하려고 할 때 인터페이스 사용

package c.service
ㅤ
import c.model.MemberDTO;
ㅤ
public interface MemberManager {
  public boolean addMember (MemberDTO member);
  public boolean removeMember (String name, String phone);
  public boolean updateMember (MemberDTO member);
}
  • 인터페이스의 선언부는 public class로 시작하지 않고 public interface로 시작

  • interface 내부에 선언된 메소드들은 몸통이 있으면 안됨
    = 메소드 선언 이후 중괄호를 열고닫거나, 중괄호안에 한줄의 코드도 있으면안됨

클래스 이름앞에 I를 붙이는 경우 O

MemberManagerImpl이라는 클래스 만들기

public class MemberManagerImpl implements MemberManger {
ㅤ
}

implements라는 단어 뒤 MemberManager라고 방금만든 인터페이스 추가
implements뒤에 인터페이스’들’ 나열

자바 상속 하나만 ?
-> implements는 상속이 아니라 해당 클래스에서 구현해야하는 인터페이스들을 정의함으로써 클래스에 짐을 지어주는 것

주의
인터페이스를 구현할 경우 (implements뒤에 인터페이스 이름을 나열할 경우)
반드시 인터페이스에 정의된 메소드들의 몸통을 만들어주어야한다.
= 즉 메소드들을 구현해야한다.

package c.service;
import c.model.MemberDTO;
public class MemberManagerImpl implements MemberManager {
  @override
  public boolean addMember(MemberDtro member) {
    return false;
  }
ㅤ
  @Override
  public boolean removeMember(String name, String phone) {
    return false; 
  }
ㅤ
  @Override
  public boolean updateMember (MemberDTO member) {
    return false; 
  }
}

-> MemberManager에 정의된 메소드들을 모두 구현해야 컴파일 정상 수행, 이제 이 클래스를 컴파일하면 정상적으로 컴파일됨 / 개발자들은 return false 부분에 실제로 해당 메소드를 실행할 수 있도록 코드 넣는 것.

@Override는 어노테이션 (Override했다는 것을 알려주는 역할)

정리
설계단계에서 인터페이스만 만들어 놓고 개발 단계에서 실제 작업을 수행하는 메소드를 만들면,
설계 단계의 산출물과 개발 단계의 산출물이 보다 효율적으로 관리됨

인터페이스 또다른 용도 : 외부 노출되는 것을 정의하려고 할 때

package c;
ㅤ
import c.service.MemberManger;
ㅤ
public class InterfaceExample {
  public static void main(String args[]) {
    MemberManger member = new MemberManager(); (X)
  }
}

InterfaceExample 클래스는 c라는 패키지이므로 c.service에 있는 MemberManager를 import해야만함
-> 에러 발생, MemberManager가 abstract이기 때문에 초기화되지 않았다는 메시지 출력
-> main메소드의 member 객체 선언 문장을 다음과 같이 변경

MemberManger member = new MemberManagerImpl();

겉보기에 member타입은 MemberManager이고 MemberManagerImpl클래스에는 인터페이스에 선언되어있는 모든 메소드들이 구현되어있음
따라서 실제 member타입은 MemberManager가 되기 때문에, member에 선언된 메소드들을 실행하면 MemberManagerImpl에 있는 메소드들이 실행됨

2. Abstract
인터페이스라고 하기도 클래스라고 하기도 애매한 abstract 클래스
abstract클래스는 자바에서 마음대로 초기화하고 실행할 수 없도록 되어있음
그래서 그 abstract 클래스를 구현해놓은 클래스로 초기화 및 실행 가능

package c.service;
ㅤ
import c.model.MemberDTO;
ㅤ
public interface MemberManager {
  public boolean addMember(MemberDTO member);
  public boolean removeMember(String name, String phone);
  public boolean updateMember (MemberDTO member);
}

인터페이스는 선언시 class X interface O (예약어)
각 메소드 선언문은 일반메소드 선언문과 동일하지만 몸통 X

package c.service;
ㅤ
import c.model.MemberDTO;
ㅤ
public abstract class MemberManagerAbstract {
  public abstract boolean addMember (MemberDTO member);
  public abstract boolean removeMember(STring name, String phone);
  public abstract boolean updateMember(MemberDTO member);
  public void printLog(String data) {
    System.out.println(“Data=” + data);
  }
}

abstract클래스 선언시 class라는 예약어 앞에 abstract이라는 예약어를 사용함
몸통없는 메소드 선언문에는 abstract이라는 예약어 명시

abstract클래스는 abstract로 선언한 메소드가 하나라도 있을 때 선언
인턴페이스와 달리 구현되어있는 메소드가 있어도 상관 X
인터페이스와 마찬가지로 파일의 확장자는 .java

정리

  • abstract 클래스는 클래스 선언시 abstract라는 예약어가 클래스 앞에 추가됨
  • abstract클래스 안에는 abstract으로 선언된 메소드가 0개 이상
  • abstract로 선언된 메소드가 하나라도 있으면 그 클래스는 반드시 abstract으로 선언되어야함
  • abstract 클래스는 몸통이 있는 메소드가 0개 이상 있어도 상관 X / static이나 final메소드가 있어도 된다. (인터페이스는 불가)

abstract클래스 역시 상속

package c.service;
ㅤ
import c.model.MemberDTO;
ㅤ
public class MemberManagerIMPl2 extends MemberManagerAbstract{
  public boolean addMember(MemberDTO member)
  return false;
}
ㅤ
  public boolean removeMember(String name, String phone) {
    return false;
  }
ㅤ
  public boolean updateMember (MemberDTO member) {
    return fasle;
  }
}

abstract 클래스 만든 이유?

  • 공통적인 기능 미리 구현해놓으면 좋음

3. Final

상속불가

package c.util;
ㅤ
public final Class FinalClass {
}

클래스 final 선언이유?
더 이상 확장하면 안되는 클래스, 누군가 이 클래스를 상속받아서 내용을 변경해서는 안되는 클래스 선언시

메소드 final 선언이유?
메소드를 final로 선언하면 더 이상 overriding불가

package c.util;
ㅤ
public abstract class FinalMethodClass {
  public final void pritnLog(String data)
System.out.println(“Data=”+data);
  }
}

그 다음 pritnLog()메소드 Overriding

package c.util;
public class FinalMethodChildClass extends FinalMethodClass {
  public void printLog(String data) {
    System.out.println(“Data=” +data);
  }
}

에러메시지 : final때문에 override불가)
final 클래스는 종종 / final 메소드는 거의 X

변수 final (다른 개념)

  • 변수를 더 이상 바꿀 수 없다라는 말
  • 변수의 생성(선언)과 동시에 초기화해야함 (인스턴스 변수 & static변수일 경우) (생성자나 메소드에서 초기화하면 안됨)
  • but 매개변수나 지역변수를 final로 선언하는 경우 반드시 선언시 초기화 필요 X
  • but 매개변수 선언시 parameter값 변경 X & 지역변수 선언시 처음 초기화 값 변경 X
  • final의 경우 절대 변하지 않는 경우에만 참조자료형에도 동일하게 적용 (dto객체, 즉 MemberDTO클래스의 객체는 한번만 생성가능)
  • but 객체 안에 있는 객체들은 final로 선언된 것이 아니기에 제약이 없다

4.Enum 클래스 (상수의 집합)
final로 String과 같은 문자열이나 숫자 (기본자료형)값 고정 가능 = 상수라고 표현 (constant)
어떤 클래스가 상수만으로 만들어져있을 경우 반드시 class로 선언할 필요는 없다.
-> 클래스 선언 부분에 enum이라고 선언하면 “이 객체는 상수의 집합”

enum = enumeration(셈, 열거)

enum 클래스 (열거형 클래스)

package c.enums;
ㅤ
public enum OverTimeValues {
  THREE_HOUR,
  FIVE_HOUR,
  WEEKEND_FOUR_HOUR,
  WEEKEND_EIGHT_HOUR;
}
  • 타입,값 지정 필요 X
  • 해당 상수 이름만 콤마로 구분하여 나열

가장 효과적 enum클래스 사용은 switch문

package c.enums;
ㅤ
public class OverTimeManger {
  public int getOverTimeAmount(OVerTimeValues value) {
    int amount = 0;
    System.out.print(value);
    switch (value) {
      case THREE_HOUR:
        amount = 18000;
        break;
      case FIVE_HOUR:
        amount = 30000;
        break;
      case WEEKEND FOUR_HOUR:
        amount=40000;
        break;
      case WEEKEND_EIGHT_HOUR:
        amount = 60000;
        break;
     }
    return amount;
  }
}
  • getOverTimeAmount() 메소드 보면 OverTimeValues라는 enum타입을 매개변수로 받고 변수명은 value로 지정
  • 야근 수당 리턴할 amount 라는 int타입을 선언하고 0을 기본값으로 선언하고 가장 마지막 줄에 그 값을 리턴
  • 메소드의 중간에는 switch문 사용, switch 조건으로 value 지정
  • switch 내 case에는 OverTimeValues에 선언한 상수 값들로 분기하도록 함

enum 타입(OverTimeValues) 을 어떻게 getOverTimeAmount() 메소드에 전달?

public static void main(String args[]) {
  OverTimeManger manager = new OverTimeManger();
  int myAmount = manager.getOverTimeAmount(OverTimeValues.THREE_HOUR);
  System.out.println(myAmount);
}

주의) THREE_HOUR 이라는 문자열만 넘긴다고 결과가 똑같이 나오지 않음

enum 상수값 지정 가능 (동적 할당은 불가)

package c.enums;
ㅤ
public enum OverTimeValues2 {
  THREE_HOUR(18000),
  FIVE_HOUR(30000),
  WEEKEND_FOUR_HOUR(40000),
  WEEKEND_EIGHT_HOUR(60000);
  private final int amount;
  OverTimeValues2 (int amount) {
  this.amount = amount;
}
  public int getAmount () {
    return amount;
  }
}
  • amount라는 변수가 final로 선언 -> OverTimeValue2의 생성자에서 매개 변수로 넘겨받은 값을 할당할 때 사용
  • enum클래스의 생성자는 아무것도 명시하지 않는 package-private과 private만 접근제어자로 사용가능
  • public protected X
  • 각 상수를 enum클래스 내에서 선언할 때만 이 생성자 사용가능
  • enum클래스 역시 컴파일시 생성자 자동생성
  • getAmount() 메소드 : enum클래스의 변수로 선언한 amount값을 리턴하기 위해

enum클래스 역시 메소드 선언해서 사용가능

package c.enums;
ㅤ
public class OverTimeManager2 {
  public static void main(String args[]) {
    OverTimeValues2 value2 = OverTimeValues2.FIVE_HOUR;
    System.out.println(value2);
    System.out.println(value2.getAmount());
  }
}

결과

FIVE_HOUR
30000

성능은 이게 좋지만 값 변경시 switch문이 더 편리
(야근 수당이 2000원 오르면 원격 서버에 있는 값을 읽어오도록하면 편리
위의 경우 자바 프로그램 수정 후 다시 컴파일해서 실행중인 자바 프로그램 중지후 시작해야한다는 단점)

enum클래스의 부모는 무조건 java.lang.Enum
(컴파일러가 알아서 extends java.lang.Enum 추가해서 컴파일)

Enum클래스 생성자
접근제어자 : protected
메소드 : Enum(String name, int ordinal)
설명 : 컴파일러에서 자동으로 호출되도록 해놓은 생성자 / 하지만 개발자가 이 생성자를 호출할 수는 없음
여기서 name = 상수이름
ordinal = enum순서 (상수 선언된 순서대로 0부터 증가)

Enum클래스의 부모클래스는 Object클래스이기 때문에 Object클래스의 메소드들은 모두 사용가능 / 하지만 Enum클래스 개발자들이 Object클래스 중 4개의 메소드를 Overriding 못하게 해놓음

Enum 클래스 막아놓은 Object 메소드
(1) clone() : 객체 복제하기 위한 메소드 (예외발생 : CloneNotSupportedException)
(2) finalize() : GC가 발생할 때 처리하기 위한 메소드
(3) hashCode() : int타입의 해시코드 값 리턴
(4) equals() : 두 객체가 동일한지 확인하는 메소드

Enum클래스에서 선언되어있는 메소드
(1) compareTo(E e) : 매개 변수로 enum타입과의 순서(ordinal)차이 리턴
(2) getDeclaringClass() : 클래스 타입의 enum을 리턴
(3) name() : 상수의 이름을 리턴
(4) ordinal() : 상수의 순서를 리턴
(5) valueOf(Class enumType, String name) : static 메소드, 첫번쨰 매개변수로 클래스 타입의 enum, 두 번째 매개변수로 상수의 이름을 넘겨줌

compareTo() 메소드 자주사용

package c.enums;
ㅤ
public class  OverTimeManager2 {
  public static void main(String args[]) {
    OverTimeValues2 value2 = OverTimeValues2.FIVE_HOUR;
    System.out.println(value2);
    System.out.println(value2.getAmount());
ㅤ
    OverTimeValues2 value3 = OverTimeValues2.THREE_HOUR;
    System.out.println(value2.compareTo(value3));
  }
}

결과

FIVE_HOUR
30000
1  // THREE_HOUR이 FIVE_HOUR  바로 앞 선언 

enum 클래스 특수 메소드 : values()
이 메소드 호출하면 enum클래스에 선언되어있는 모든 상수를 배열로 리턴
어떤 상수가 어떤 순서로 선언되었는지 확인하기 어려운 경우 이 메소드 사용하면 도움됨

package c.enums;
ㅤ
public class OverTimeManager3 {
  public static void main(String args[]) {
    OverTimeValues2 []valueList = OverTimeValues2.values();
    for(OverTimeValues2 value:valueList) {
      System.out.println(value);
    }
  }
}

좋은 웹페이지 즐겨찾기