1. 객체-지향 프로그래밍
1.1 개요 소프트웨어 공학 하향식 설계 모듈화 정보 은폐 객체 지향 프로그래밍 프로그램: 대화식 객체들의 결합 객체: 윈도우나 사람과 같은 실체들에 대한 추상적인 표현
문제 풀이 컴퓨터 프로그램 = 솔루션(해답) 예: 계산기 응용 소프트웨어 개발 프로세스 일련의 상이한 단계들로 구성
소프트웨어 솔루션 생애의 단계
가능성 연구 요구사항 분석 프로젝트 설계 구현 테스팅 유지보수 문제에 대한 명확한 문장과 그에 대한 솔루션의 잠재적 이득에 대한 분석 자료 도출 문제를 풀기 위한 자원, 개발 기간, 성공시 예상 이윤 추정 요구사항 분석 최종 제품이 수행해야 할 사항을 명확하게 정의하는 문서 생성 사용자 매뉴얼 초안 작성 프로젝트 설계 소프트웨어 시스템의 전체적인 구조 결정 개별 컴포넌트 식별, 각 컴포넌트가 수행할 사항 명세 구현 각 컴포넌트에 대해 실행 가능한 코드 생성 테스팅 요구 사항 명세에 대비한 전체 시스템 테스트 유지보수 사용자 지원, 패치판(서비스 팩), 개정판 포함
소프트웨어 단계 일련의 단계들이 실제로는 여러 번 반복됨
예제: 온도 단위 변환기 가능성 연구 요구사항 분석 섭씨를 화씨로 변환, 그 역으로도 변환 개발 기간은 오늘 Keep it simple, stupid 원리 고수 키보드에서 입력을 읽어 콘솔 윈도우에 출력하는 Java 프로그램 개발 입력 값들을 args[] 배열에 저장 Java Convert <숫자> <단위> Netbeans IDE : choose project – click right mouse – choose propertied – choose run category – put input values in arguments field 사용자 매뉴얼 작성
Convert 프로그램의 테스팅
온도 변환 솔루션의 사용자 매뉴얼
1.2 객체-지향 설계 객체, 클래스, 인터페이스 명세 Java는 거대한 표준 라이브러리 지원 사전 제조 소프트웨어 -> 재사용 해당 타입을 Java 인터페이스로 명세 온도 변환 예: 리스팅 1.1 설명문 /* C 스타일 */ // C++ 스타일 /** Javadoc 설명문 */ 해당 메소드들을 Javadoc 문서 유틸리티를 이용해 기술 xx.java 파일을 xx.html 파일로 생성 Javadoc 웹 페이지: java 타입(인터페이스나 클래스)이 할 수 있는 일을 문서화 추상화: 공적인 “무엇”을 사적인 “어떻게”와 분리
온도 변환 문제를 위한 Java 인터페이스 1 /** 2 * An interface for representing temperatures, with functionality 3 * for converting their values between Celsius and Fahrenheit. 4 * @author John R. Hubbard 5 * @see MyTemperature 6 */ 8 public interface Temperature { 9 /** @return the Celsius value for this temperature. */ 10 public double getCelsius(); 12 /** @return the Fahrenheit value for this temperature. */ 13 public double getFahrenheit(); 15 /** @param celsius the Celsius value for this temperature. */ 16 public void setCelsius(double celsius); 18 /** @param fahrenheit the Fahrenheit value for this temperature.*/ 19 public void setFahrenheit(double fahrenheit); 20 }
리스팅 1.1에서 생성된 Javadoc 화일
온도 단위 변환기의 알고리즘 변환 공식 F = 9C/5 + 32 C = 5(F-32)/9 알고리즘 1.1, 1.2
1.3 소프트웨어 설계의 구현 설계 팀이 구현 팀에 관련 문서 전달 사용자 매뉴얼: 그림 1.5 솔루션 개요: 알고리즘 1.1 변환 공식: 알고리즘 1.2 Temperature 인터페이스: 리스팅 1.1 구현 팀은 각 컴포넌트를 구현하고 이를 조립해 솔루션을 만들어 냄 Temperature 객체의 데이터 double 타입의 private 인스턴스 변수 변수의 값은 온도의 섭씨 값 4개 메소드, 생성자, toString(), round() 메소드로 구성 결과: 리스팅 1.2
Temperature 인터페이스의 구현 LISTING 1.2: An Implementation of the Temperature Interface 1 public class MyTemperature implements Temperature { 2 private double celsius; // stores temperature as a Celsius value 3 4 public MyTemperature(double value, char scale) { 5 if (scale=='C') setCelsius(value); 6 else setFahrenheit(value); 7 } 8 9 public double getCelsius() { 10 return celsius; 11 } 12 13 public double getFahrenheit() { 14 return 9*celsius/5 + 32.0; 15 }
17 public void setCelsius(double celsius) { 18 this.celsius = celsius; 19 } 21 public void setFahrenheit(double fahrenheit) { 22 this.celsius = 5*(fahrenheit - 32)/9; 23 } 25 public String toString() { 26 // Example: "25.0 C = 77.0 F" 27 return round(getCelsius())+ " C = " + round(getFahrenheit())+ " F"; 28 } 30 private double round(double x) { 31 // returns x, rounded to one digit on the right of the decimal: 32 return Math.round(10*x)/10.0; 33 } 34 }
1.4 클래스의 테스팅 개발 프로세스에서 가장 어렵고 중요한 부분 테스트 드라이버 프로그램 어려운 이유: 가능한 조건의 극히 일부만 테스팅 가능 중요한 이유: 이 단계에서 대부분의 에러를 찾아 제거 테스트 드라이버 프로그램 리스팅 1.3
Temperature 프로그램에 대한 솔루션의 테스팅 LISTING 1.3: Testing the Solution to the Temperature Problem 1 public class Convert { 2 public static void main(String[] args) { 3 if (args.length!=2) exit(); 4 double value = Double.parseDouble(args[0]); // convert string 5 char scale = Character.toUpperCase(args[1].charAt(0)); 6 if (scale != 'C' && scale != 'F') exit(); 7 Temperature temperature = new MyTemperature(value,scale); 8 System.out.println(temperature); 9 } 11 private static void exit() { 12 // prints usage message and then terminates the program: 13 System.out.println( 14 "Usage: java Convert <temperature> <scale>" 15 + "\nwhere:" 16 + "\t<temperature> is the temperature that you want to convert" 17 + "\n\t<scale> is either \"C\" or \"F\"." 18 + "\nExample: java Convert 67 F" 19 ); 20 System.exit(0); 21 } 22 }
스텁(stub) 대형 클래시 개발 시 초기에 메소드에 대한 스텁 작성 스텁이란 본체가 빈 메소드; 컴파일에 필요한 정도의 코드만 가지고 전체 구현은 테스트될 때까지 미루어짐 예: 카티션 공간의 점 (x,y)를 표현하는 클래스의 메소드들 스텁을 가진 클래스의 구현: 리스팅 1.4 생성자와 toString() 메소드 이외의 모든 메소드가 스텁인 상태 12개의 스텁 각각은 최소한으로 구현 void 메소드: 빈 블록 비-void 메소드: return 문만 가짐 이 미완성 클래스는 컴파일과 테스트가 가능함 다음으로 다른 메소드를 완성하고 클래스를 다시 컴파일하고 테스트 -> 모든 메소드가 완성이 될 때까지 이 프로세스를 반복
Point(double, double) // 점 (x,y)를 생성 void add(double, double) // 주어진 변위 (dx,dy)를 더함 void add(Point) // 주어진 점을 더함 double amplitude() // 라디안 각을 리턴 boolean equals(Object) // Object.equals() 메소드를 오버라이드 void expand(double) // 주어진 인자를 곱함 double x() // x-좌표를 리턴 double y() // y-좌표를 리턴 double modulus() // (0,0)에 대한 거리를 리턴 void moveTo(double, double) // 주어진 (x,y) 위치로 이동 void moveTo(Point) // 주어진 점으로 이동 void rotate(double) // 주어진 라디안 각 만큼 회전 String toString() // Object.toString() 메소드를 오버라이드
스텁을 가진 Point 클래스의 구현 LISTING 1.4: Implementing a Point Class with Stubs 1 public class Point { 2 private double x, y; 3 public static final Point ORIGIN = new Point(); 5 private Point() { } 8 public Point(double x, double y) { 9 this.x = x; 10 this.y = y; } 13 public void add(double u, double v) { } 14 public void add(Point p) { } 15 public double amplitude() { return 0.0; } 16 public static double distance(Point p, Point q) { return 0.0; } 17 public boolean equals(Object object) { return false; } 18 public void expand(double c) { } 19 public double x() { return 0.0; } 20 public double y() { return 0.0; } 21 public double modulus() { return 0.0; } 22 public void moveTo(double x, double y) { } 23 public void moveTo(Point p) { } 24 public void rotate(double t) { } 26 public String toString() { 27 return "(" + x + "," + y + ")"; 28 } 29 }
1.5 알고리즘의 구현과 테스팅 소수(prime number)를 찾는 알고리즘 소수 소수를 찾는 알고리즘: 알고리즘 1.3 1보다 큰 정수로 1과 그 자신 이외에는 제수(divisor)가 없는 수 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, … 소수를 찾는 알고리즘: 알고리즘 1.3 구현 리스팅 1.5 테스팅 1에서 30까지의 모든 정수 테스트 1에서 100까지의 모든 정수 테스트 경계값(boundary value) 다른 값들처럼 보편적이지는 않는 끝점이나 기타 특별한 값 후보: 범위의 최소값과 최대값, 공백 문자열이나 단일 문자열, null 참조 등 경계값을 고려한 테스트 드라이버: 리스팅 1.6
소수를 찾는 알고리즘 ▲ 알고리즘 1.3: 소수 --------------------------------- 입력: 정수 n 4. 3부터 n까지의 모든 홀수 d에 대해 단계 5를 반복: 5. n을 d로 나눌 수 있으면 거짓을 리턴 6. 참을 리턴 소수(prime number) 란? 1 보다 큰 정수로 1과 그 자신 이외에는 제수(divisor)가 없는 수 처음 10개의 소수는 2, 3, 5, 7, 11, 13, 17, 19, 23, 29이다.
소수 탐색 LISTING 1.5: Finding Prime Numbers 1 public static boolean isPrime(int n) { 2 if (n < 2) return false; 3 if (n < 4) return true; 4 if (n%2 == 0) return false; 5 for (int d=3; d*d <= n; d += 2) 6 if (n%d == 0) return false; 7 return true; 8 }
소수 알고리즘의 테스팅 LISTING 1.6: Testing the Prime Number Algorithm 1 public class TestPrimeAlgorithm { 2 public static void main(String[] args) { 3 for (int n=-10; n <= 100; n++) 4 if (isPrime(n)) System.out.print(n + " "); 5 } 6 7 public static boolean isPrime(int n) { 8 // See Listing 1.5 on page 14. 9 } 10}
UML UML (Unified Modeling Language) 객체 지향 소프트웨어를 모델링하기 위한 시각적 명세 언어 OMG (Object Management Group)에 의해서 1997년에 표준안으로 채택 클래스를 명세하는 다이어그램 3개 부분으로 구성: 클래스 이름, 필드들, 메소드들 접근 범주: +(public), -(private), #(protected) 클래스 필드: 상태(데이터)를 정의 클래스 메소드: 행위(연산)를 정의 예: Person 클래스 UML 다이어그램: 그림 1.7 클래스 정의: 리스팅 1.7 예: 차를 타는 사람들의 시뮬레이션 Person 클래스와 Car 클래스 필요: 그림 1.9
Person 클래스에 대한 UML 명세
Person 클래스 1 public class Person { 2 protected boolean male; 3 protected String name; 4 protected Phone phone; 5 protected int yob; 7 public Person(String name, boolean male, int yob) { 8 this.name = name; 9 this.male = male; 10 this.yob = yob; 11 } 13 public String getName() { 14 return name; 15 } 17 public Phone getPhone() { 18 return phone; 19 } 21 public int getYob() { 22 return yob; 23 } 25 public boolean isMale() { 26 return male; 27 } 29 public void setPhone(Phone phone) { 30 this.phone = phone; 31 } 32}
UML 템플리트 상태와 행위
Person 클래스와 Car 클래스
1.7 계승, 집단, 합성 클래스가 다른 클래스의 일부분이 될 수 있는 방법 계승 (inheritance) 다른 객체의 세분(specialization) 예: 개 is-a 포유동물, 트럭 is-a 차량, 책 is-a 인쇄매체 집단 (aggregation) 다른 독립적인 객체들의 그룹핑 예: 집합은 원소들의 그룹, NATO 연방은 참가국가의 그룹 has-a 관계: 집합 has an 원소 합성 (composition) 다른 객체들을 포함하는 것 개는 심장을 포함, 트럭은 엔진을 포함, 집합은 부분집합을 포함 contains-a 관계: 집합 contains 부분집합
클래스간의 관계에 대한 UML 기호
예, 대학 등록 시스템을 위한 클래스 과목, 과목의 섹션, 학생, 강사와 같은 객체들로 구성 학생과 강사는 사람의 특별한 타입들 과목은 섹션을 포함 섹션의 존재는 그 것을 포함하는 과목의 존재에 종속 하나의 섹션은 오직 하나의 과목에만 소속 하나의 섹션은 그 섹션에 등록한 학생들과 그 섹션을 가르치는 하나의 강사를 가짐 학생과 강사 자체는 섹션과 독립적으로 존재
대학 등록 시스템을 위한 5개 클래스
클래스들간의 관계
계승의 구현 집단의 구현 합성의 구현 클래스 B extend 클래스 A 클래스 A 내부에 클래스 B 타입의 필드를 선언 내부 클래스로 포함 예: Student 클래스와 Transcript(성적표) 클래스
계승과 집단의 구현 LISTING 1.8: Implementing Inheritance and Aggregation 1 public class Student extends Person { // Student inherits Person 2 protected String country; // Student aggregates String 3 protected int credits; 4 protected double gpa; 5 6 public Student(String name, boolean male, int yob, String country) { 7 super(name, male, yob); 8 this.country = country; 9 } 10 }
합성 구현(Implementing Composition) 1 public class Student extends Person { // inheritance 2 private String country; // aggregation 3 private int credits; 4 private double gpa; 5 private final Transcript transcript = new Transcript(); 7 public Student(String name, boolean male, int yob, String country) { 8 super(name, male, yob); 9 this.country = country; 10 } 12 public void updateTranscript(Section section, Grade grade) { 13 transcript.add(section, grade); 14 } 16 public void printTranscript() { 17 System.out.println(transcript); 18 } 20 private class Transcript { // composition 21 // internal fields... 22 void add(Section section, Grade grade) { //... 23 public String toString() { //... 24 } 25 }
클래스간의 관계
1.8 가변 객체와 불변 객체 불변 (immutable) 객체 가변 (mutable) 객체 데이터를 변경할 수 없는 객체 예: Java에서 String 객체 가변 (mutable) 객체 데이터를 변경할 수 있는 객체 예: Java에서 StringBuffer 객체 새로운 클래스 생성시 -> 가변 클래스가 됨 예: 리스팅 1.7의 Person 클래스 클래스를 불변 클래스로 변경 set 메소드를 제거하고 생성자를 변경 모든 필드를 private로 선언 모든 필드를 final로 명세: 그림 1.13, 리스팅 1.10 -> 아직 부족함 Phone 객체를 Person 객체안에 완전히 캡슐화시켜 모든 외부 접근을 차단: 리스팅 1.12 불변 클래스의 장점 상이한 인스턴스들이 동일 데이터를 공유할 수 있음 예: java.math.BigInteger 클래스
수정된 Person 클래스
수정된 Person 클래스 LISTING 1.10 A Revised Person Class 1 public class Person { 2 protected final boolean male; 3 protected final String name; 4 protected final Phone phone; 5 protected final int yob; 7 public Person(String name, boolean male, int yob, Phone phone) { 8 this.name = name; 9 this.male = male; 10 this.yob = yob; 11 this.phone = phone; 12 } 14 public String getName() { 15 return name; 16 } 18 public Phone getPhone() { 19 return phone; 20 } 22 public int getYob() { 23 return yob; 24 } 26 public boolean isMale() { 27 return male; 28 } 29 }
가변 Phone 클래스 LISTING 1.11: A Mutable Phone Class 1 class Phone { 2 private String areaCode, number; 3 4 public Phone(String areaCode, String number) { 5 this.areaCode = areaCode; 6 this.number = number; 7 } 8 9 public void setAreaCode(String areaCode) { 10 this.areaCode = areaCode; 11 } 12 }
가변 Person 객체
불변 Person 클래스 LISTING 1.12: An Immutable Person Class 1 public class Person { 2 // INVARIANT: all instances are immutable; 3 protected final boolean male; 4 protected final String name; 5 protected final Phone phone; 6 protected final int yob; 8 public Person(String name, boolean male, int yob, Phone phone) { 9 this.name = name; 10 this.male = male; 11 this.yob = yob; 12 this.phone = new Phone(phone); 13 } 14 // Lines 14-28 from Listing 1.10 on page 23 go here. 16 }
불변 Person 객체
동일한 Phone 객체를 공유하는 불변 Person 객체 LISTING 1.13: Immutable Person Objects Sharing the Same Phone Object 1 public Person(String name, boolean male, int yob, Person friend) { 2 this.name = name; 3 this.male = male; 4 this.yob = yob; 5 this.phone = friend.phone; 6 }
수정된 Person 클래스에 대한 테스트 드라이버 LISTING 1.14: A Test Driver for the Revised Person Class 1 public class TestPerson { 2 public static void main(String[] args) { 3 Phone p = new Phone("804", "3790550"); 4 Person john = new Person("John Adams", true, 1980, p); 5 System.out.println(john); 6 Person jane = new Person("Jane Adams", false, 1981, john); 7 System.out.println(jane); 8 john = null; 9 System.out.println(jane); 10 } 11 }
출력 결과 Mr. John Adams (1980), tel. (804)379-0550 Ms. Jane Adams (1981), tel. (804)379-0550 Ms. Jane Adams (1981), tel. (804)379-0550
하나의 Phone 객체를 공유하는 두 Person 객체