객체 지향 디자인 Object-Oriented Design 제 6 장 객체 지향 디자인 Object-Oriented Design
객체지향 디자인 이 장에서는 클래스와 객체의 디자인 방법에 대해 알아본다. 6장의 주요 내용: 소프트웨어 개발 과정 이 장에서는 클래스와 객체의 디자인 방법에 대해 알아본다. 6장의 주요 내용: 소프트웨어 개발 과정 프로그램에 필요한 클래스와 객체의 결정 클래스 사이의 관계 static 조정자 인터페이스 작성 열거 타입 메쏘드 설계와 메쏘드 중복정의 GUI 설계와 레이아웃 관리자 © 2004 Pearson Addison-Wesley. All rights reserved
목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces) 열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout) © 2004 Pearson Addison-Wesley. All rights reserved
소프트웨어 개발 소프트웨어 개발 과정: 위의 개발활동은 순차적이지 않고 단계가 중복되거나 상호작용 된다. 요구사항 분석 (establishing the requirements) 설계 (creating a design) 코드 구현 (implementing the code) 테스트 (testing the implementation) 위의 개발활동은 순차적이지 않고 단계가 중복되거나 상호작용 된다. © 2004 Pearson Addison-Wesley. All rights reserved
소프트웨어 개발 과정 요구 요구사항 분석 설계 구현 테스트 유지보수 © 2004 Pearson Addison-Wesley. All rights reserved
요구사항 소프트웨어 요구사항 초기 요구사항 프로그램이 하고자 하는 일들을 명시하는 것이다. 어떻게(How) 할 것인가가 아닌 무엇(What)을 할 것인가! 초기 요구사항 불완전하기 때문에 신중히 분석되고 확장되어 다듬어져야 된다. 자세하고 명료한 완전한 요구사항을 제정하는 것은 힘든 일이다. © 2004 Pearson Addison-Wesley. All rights reserved
설계(Design) 소프트웨어 설계 객체지향 설계 저 수준 설계 소프트웨어의 요구사항을 어떻게(How) 달성할지 결정하는 것 어떻게 해답을 관리 가능한 작은 모듈들로 나눌 것인가? 각각의 모듈들은 무엇을 할 것인가? 객체지향 설계 프로그램에 필요한 클래스와 객체 들을 명시하고 그들이 어떻게 상호작용 하는지 결정한다. 저 수준 설계 각 메쏘드가 일을 수항하는 방법도 포함한다. © 2004 Pearson Addison-Wesley. All rights reserved
구현 구현 초보 프로그래머 생각 대부분의 중요한 결정 설계내용을 소스 코드로 작성하는 과정이다. 코드 작성을 소프트웨어 개발의 핵심으로 생각하고 있는데 사실 코딩은 가장 덜 창조적인 작업이다. 대부분의 중요한 결정 요구사항을 결정하고 설계를 수행하는 단계에서 하게 된다. © 2004 Pearson Addison-Wesley. All rights reserved
테스트 테스트 디버깅(Debugging) QnA 프로그램이 수행될 조건 하에서 의도한 문제를 제대로 해결하는지 확인하는 작업이다. 프로그램은 오류를 찾기 위해 철저히 테스트되어야 한다. 디버깅(Debugging) 문제의 원인을 찾고 올바르게 고치는 작업이다. QnA 디버깅 무슨 뜻이지요? © 2004 Pearson Addison-Wesley. All rights reserved
목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces) 열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout) © 2004 Pearson Addison-Wesley. All rights reserved
클래스와 객체의 식별 객체지향 설계의 핵심 잠재적인 클래스를 식별 법 클래스들의 사용/작성 클래스와 객체들의 식별 프로그램 요구사항에서 논의된 객체들을 먼저 식별 객체는 일반적으로 명사이고 객체가 제공하는 서비스는 일반적으로 동사이다. 클래스들의 사용/작성 클래스 라이브러리에 있는 것 이전 프로젝트에서 만들었던 것을 재사용 혹은 새로 작성 © 2004 Pearson Addison-Wesley. All rights reserved
클래스와 객체의 식별 문제 명세의 일부: The user must be allowed to specify each product by its primary characteristics, including its name and product number. If the bar code does not match the product, then an error should be generated to the message window and entered into the error log. The summary report of all transactions must be structured as specified in section 7.A. 물론 문제 명세에서 모든 명사들이 프로그램의 클래스나 객체에 해당하는 것은 아니다. © 2004 Pearson Addison-Wesley. All rights reserved
클래스와 객체의 식별 클래스 객체 생성 비슷한 행동을 하는 객체들의 그룹을 표현한다. 클래스는 객체의 개념을 표현하는 정의 예: Coin, Student, Message 클래스는 필요한 만큼의 자세한 내용이 정의되어야 한다. 객체 생성 클래스로부터 필요한 만큼의 객체를 메모리가 허용하는 범위 안에서 제한 없이 생성할 수 있다. © 2004 Pearson Addison-Wesley. All rights reserved
목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces) 열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout) © 2004 Pearson Addison-Wesley. All rights reserved
정적 클래스 멤버 정적 메쏘드(static method) result = Math.sqrt(25) 변수도 정적일 수 있다. 객체 생성 없이 클래스 이름으로 호출 가능하다. 예, Math 클래스의 메쏘드 들은 정적 메쏘드 이다: result = Math.sqrt(25) 변수도 정적일 수 있다. 정적 메쏘드나 변수를 만드는 것은 프로그램 설계에 있어 중요한 결정이다. © 2004 Pearson Addison-Wesley. All rights reserved
static 조정자 (static Modifier) 정적 메쏘드와 정적 변수 선언 static 조정자(modifier) 사용 예, static int count; 정적 변수 public static int counter (int num) 정적 메쏘드 정적 메쏘드/정적 변수는 객체가 아닌 클래스 자체에 연계된다. 클래스 메쏘드 (class method) 혹은 클래스 변수 (class variable)라고도 부른다. © 2004 Pearson Addison-Wesley. All rights reserved
정적 변수(Static Variables) 실체 변수(instance variable) 각 객체(실체) 별로 별도의 기억공간 가짐 정적 변수(static variable) 하나의 기억공간만 존재하고 클래스의 모든 객체들이 이를 공유 private static float price; 따라서, 어떤 클래스의 한 객체 내에서 정적 변수의 값을 변경하면 그 클래스의 다른 모든 객체의 것을 바꾸게 된다. © 2004 Pearson Addison-Wesley. All rights reserved
정적 메쏘드 호출(Static Method) class Helper { public static int cube (int num) return num * num * num; } cube 메쏘드는 정적 메쏘드이기 때문에 다음과 같이 호출 된다. value = Helper.cube(5); 클래스 이름 메쏘드 이름 © 2004 Pearson Addison-Wesley. All rights reserved
정적 클래스 멤버(Static Class Member) main 메쏘드는 정적 메쏘드 따라서 객체의 생성 없이 Java 인터프리터로부터 직접 호출된다. 정적 메쏘드는 실체 변수를 참조할 수 없다. Why? 실체 변수는 클래스의 객체가 생성되기 전에는 존재하지 않기 때문. 그러나, 정적 메쏘드는 정적 변수나 지역 변수는 참조 가능 다음 예제 프로그램 정적 변수를 사용하여 Slogan 객체가 몇 개가 생성되었는지를 감지하고 정적 메쏘드를 사용하여 그 정보를 확인할 수 있게 한다. SloganCounter.java (국: 299쪽,영:294쪽) 참조 Slogan.java (국:301쪽,영: 295쪽) 참조 © 2004 Pearson Addison-Wesley. All rights reserved
SloganCounter.java //******************************************************************* // SloganCounter.java 저자: 루이스와 롭터스 // static 조정자의 사용을 보인다. public class SloganCounter { //---------------------------------------------------------------- // 여러 개의 Slogan 객체들을 생성하고 생성된 객체들의 수를 프린트한다. public static void main (String[] args) { Slogan obj; obj = new Slogan ("Remember the Alamo."); System.out.println (obj); obj = new Slogan ("Don't Worry. Be Happy."); © 2004 Pearson Addison-Wesley. All rights reserved
SloganCounter.java (cont’d) obj = new Slogan ("Live Free or Die."); System.out.println (obj); obj = new Slogan ("Talk is Cheap."); obj = new Slogan ("Write Once, Run Anywhere."); System.out.println(); System.out.println ("Slogans created: " + Slogan.getCount()); } } 출력: Remember the Alamo. Don't Worry. Be Happy. Live Free or Die. Talk is Cheap. Write Once, Run Anywhere. Slogans created: 5 © 2004 Pearson Addison-Wesley. All rights reserved
Slogan.java © 2004 Pearson Addison-Wesley. All rights reserved
목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces) 열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout) © 2004 Pearson Addison-Wesley. All rights reserved
클래스 관계(Class Relationships) 클래스들 사이의 관계 의존성(Dependency): A uses B 집합체(Aggregation): A has-a B 상속(Inheritance): A is-a B 이 장에서는 의존성과 집합체만을 다루고 상속은 8장에서 다루도록 한다. © 2004 Pearson Addison-Wesley. All rights reserved
의존성(Dependency) 한 클래스가 다른 클래스에 의존한다는 것은 한 클래스 안의 다른 객체 사이에 의존성도 가능 다른 클래스의 메쏘드를 호출할 때 “uses” 관계가 됨 클래스들의 의존성이 균형 있게 설계되어야 한다. 한 클래스 안의 다른 객체 사이에 의존성도 가능 한 클래스의 메쏘드가 같은 클래스의 다른 객체를 매개변수로 받을 수 있다. 예, String 클래스의 concat 메쏘드는 다른 String 객체를 매개변수로 받는다. str3 = str1.concat(str2); © 2004 Pearson Addison-Wesley. All rights reserved
의존성(Dependency) 예제 RationalTester.java (국: 303쪽, 영: 297쪽) 참조 유리수는 두 정수의 비로 표현할 수 있는 값이다. Rational 클래스의 몇몇 메쏘드들은 다른 Rational 객체를 매개변수로 받고 있다. RationalTester.java (국: 303쪽, 영: 297쪽) 참조 RationalNumber.java (국: 305쪽, 영: 299쪽) 참조 © 2004 Pearson Addison-Wesley. All rights reserved
RationalTester.java //******************************************************************* // RationalTester.java 저자: 루이스와 롭터스 // 여러 Rational 객체의 사용을 시험하는 드라이버. public class RationalTester { //--------------------------------------------------------------- // 몇 개의 유리수 객체들을 만들어 다양한 연산을 수행한다. public static void main (String[] args) { Rational r1 = new Rational (6, 8); Rational r2 = new Rational (1, 3); Rational r3, r4, r5, r6, r7; © 2004 Pearson Addison-Wesley. All rights reserved
RationalTester.java (Cont’d) System.out.println ("First rational number: " + r1); System.out.println ("Second rational number: " + r2); if (r1.equals(r2)) System.out.println ("r1 and r2 are equal."); else System.out.println ("r1 and r2 are NOT equal."); r3 = r1.reciprocal(); System.out.println ("The reciprocal of r1 is: " + r3); © 2004 Pearson Addison-Wesley. All rights reserved
RationalTester.java (Cont’d) r4 = r1.add(r2); r5 = r1.subtract(r2); r6 = r1.multiply(r2); r7 = r1.divide(r2); System.out.println ("r1 + r2: " + r4); System.out.println ("r1 - r2: " + r5); System.out.println ("r1 * r2: " + r6); System.out.println ("r1 / r2: " + r7); } } 출력 ======================= First relational number: 3/4 Second relational number; 1/3 r1 and r2 are NOT equal. The reciprocal of r1 is: 4/3 r1 + r2: 13/12 r1 - r2: 5/12 r1 * r2: 1/4 r1 / r2: 9/4 © 2004 Pearson Addison-Wesley. All rights reserved
RationalNumber.java //******************************************************************* // RationalNumber.java 저자: 루이스와 롭터스 // 분자와 분모를 가진 유리수를 표현한다. public class RationalNumber { private int numerator, denominator; //---------------------------------------------------------------- // 구성자: 0이 아닌 분모를 갖고 부호가 있는 분자를 갖도록 // 유리수를 설정한다. public RationalNumber (int numer, int denom) { if (denom == 0) denom = 1; © 2004 Pearson Addison-Wesley. All rights reserved
RationalNumber.java (cont’d) // 부호를 갖는 분자를 만든다. if (denom < 0) { numer = numer * -1; denom = denom * -1; } numerator = numer; denominator = denom; reduce(); } //---------------------------------------------------------------- // 이 유리수의 분모를 반환한다. //---------------------------------------------------------------- public int getNumerator () { return numerator; © 2004 Pearson Addison-Wesley. All rights reserved
RationalNumber.java (cont’d) //---------------------------------------------------------------- // 이 유리수의 분자를 반환한다. //---------------------------------------------------------------- public int getDenominator () { return denominator; } //---------------------------------------------------------------- // 이 유리수의 역수를 반환한다. public RationalNumber reciprocal () return new RationalNumber (denominator, numerator); © 2004 Pearson Addison-Wesley. All rights reserved
RationalNumber.java (cont’d) //---------------------------------------------------------------- // 이 유리수를 매개변수로 전달된 유리수에 더한다. // 각 분모를 곱해서 공통분모를찾는다. //---------------------------------------------------------------- public RationalNumber add (RationalNumber op2) { int commonDenominator = denominator * op2.getDenominator(); int numerator1 = numerator * op2.getDenominator(); int numerator2 = op2.getNumerator() * denominator; int sum = numerator1 + numerator2; return new RationalNumber (sum, commonDenominator); } © 2004 Pearson Addison-Wesley. All rights reserved
RationalNumber.java (cont’d) //---------------------------------------------------------------- // 이 유리수에서 매개변수로 받은 유리수를 뺀다. public RationalNumber subtract (RationalNumber op2) { int commonDenominator = denominator * op2.getDenominator(); int numerator1 = numerator * op2.getDenominator(); int numerator2 = op2.getNumerator() * denominator; int difference = numerator1 - numerator2; return new RationalNumber (difference, commonDenominator); } © 2004 Pearson Addison-Wesley. All rights reserved
RationalNumber.java (cont’d) //---------------------------------------------------------------- // 이 유리수를 매개변수로 받은 유리수와 곱한다. //---------------------------------------------------------------- public RationallNumber multiply (RationallNumber op2) { int numer = numerator * op2.getNumerator(); int denom = denominator * op2.getDenominator(); return new RationallNumber (numer, denom); } © 2004 Pearson Addison-Wesley. All rights reserved
RationalNumber.java (cont’d) //---------------------------------------------------------------- // 이 유리수를 매개변수로 받은 유리수로 나눈다. // 두 번째 피연산자의 역수를 곱함으로써 나눗셈을 한다. public RationallNumber divide (RationallNumber op2) { return multiply (op2.reciprocal()); } // 유리수가 전달된 매개변수와 같은지 결정한다. // 둘 다 약분되었다고 가정한다. public boolean equals (RationallNumber op2) return ( numerator == op2.getNumerator() && denominator == op2.getDenominator() ); © 2004 Pearson Addison-Wesley. All rights reserved
RationalNumber.java (cont’d) //---------------------------------------------------------------- // 이 유리수를 스트링으로 반환하다. public String toString () { String result; if (numerator == 0) result = "0"; else if (denominator == 1) result = numerator + ""; else result = numerator + "/" + denominator; return result; } © 2004 Pearson Addison-Wesley. All rights reserved
RationalNumber.java (cont’d) //---------------------------------------------------------------- // 최대공약수로 분모와 분자를 나눔으로써 유리수를 약분한다. private void reduce () { if (numerator != 0) { int common = gcd (Math.abs(numerator), denominator); numerator = numerator / common; denominator = denominator / common; } } © 2004 Pearson Addison-Wesley. All rights reserved
RationalNumber.java (cont’d) //---------------------------------------------------------------- // 매개변수로 받은 두 개의 양수의 최대공약수를 계산하여 반환한다. // 유클리드 알고리즘을 이용한다. private int gcd (int num1, int num2) { while (num1 != num2) if (num1 > num2) num1 = num1 - num2; else num2 = num2 - num1; return num1; } } © 2004 Pearson Addison-Wesley. All rights reserved
집합체(Aggregation) 집합체 객체(aggregate object) 다른 객체들로 구성된 객체를 말한다. 따라서 집합체(aggregation)는 ‘has-a’ 관계를 갖는다. A car has a chassis (예, 자동차는 차대를 갖는다) 실체 데이터로 다른 객체들에 대한 참조를 포함한다. 집합체 객체는 그것을 이루는 객체들에 의해 요소 별로 정의된다. © 2004 Pearson Addison-Wesley. All rights reserved
집합체(Aggregation) 예제 UML에서 집합체 Student 객체는 부분적으로 두 개의 Address 객체들로 구성되어 있다. student는 두 개의 주소를 갖는다 (학교, 집) StudentBody.java (국: 309쪽, 영: 304쪽) 참조 Student.java (국: 310쪽, 영: 306쪽) 참조 Address.java (국: 311쪽, 영: 307쪽) 참조 UML에서 집합체 두 클래스 사이에 선으로 표현되는데 집합체 클래스 부근에 끝이 다이아몬드인 선으로 표현된다. © 2004 Pearson Addison-Wesley. All rights reserved
UML에서의 집합체 StudentBody Student Address - firstName : String + main (args : String[]) : void + toString() : String Student - firstName : String - lastName : String - homeAddress : Address - schoolAddress : Address - streetAddress : String - city : String - state : String - zipCode : long Address © 2004 Pearson Addison-Wesley. All rights reserved
StudentBody.java //******************************************************************* // StudentBody.java 저자: 루이스와 롭터스 // 집합체 클래스 사용을 보인다. public class StudentBody { //---------------------------------------------------------------- // 몇 개의 Address와 Student 객체들을 생성하고 프린트한다. public static void main (String[] args) { Address school = new Address ("800 Lancaster Ave.", "Villanova", "PA", 19085); Address jHome = new Address ("21 Jump Street", "Lynchburg", "VA", 24551); Student john = new Student ("John", "Smith", jHome, school); © 2004 Pearson Addison-Wesley. All rights reserved
StudentBody.java (Cont’d) Address mHome = new Address ("123 Main Street", "Euclid", "OH", 44132); Student marsha = new Student ("Marsha", "Jones", mHome, school); System.out.println (john); System.out.println (); System.out.println (marsha); } } 출력: John Smith Home Address: 21 Jump Street Lynchburg, VA 24551 School Address: 800 Lancaster Ave. Villanova, PA 19085 Marsha Jones 123 Main Street Euclid, OH 44132 ….. © 2004 Pearson Addison-Wesley. All rights reserved
Student.java //******************************************************************* // Student.java 저자: 루이스와 롭터스 // 대학생을 표현한다. public class Student { private String firstName, lastName; private Address homeAddress, schoolAddress; //---------------------------------------------------------------- // 구성자: 학생을 명시된 값으로 설정한다. public Student (String first, String last, Address home, Address school) { firstName = first; lastName = last; homeAddress = home; schoolAddress = school; } © 2004 Pearson Addison-Wesley. All rights reserved
Student.java (Cont’d) //---------------------------------------------------------------- // 이 Student 객체에 대한 스트링 표현을 반환한다. //---------------------------------------------------------------- public String toString() { String result; result = firstName + " " + lastName + "\n"; result += "Home Address:\n" + homeAddress + "\n"; result += "School Address:\n" + schoolAddress; return result; } } © 2004 Pearson Addison-Wesley. All rights reserved
Address.java //******************************************************************* // Address.java Author: Lewis/Loftus // 거리 주소를 표현한다. public class Address { private String streetAddress, city, state; private long zipCode; //---------------------------------------------------------------- // 구성자: 이 주소를 명시된 데이터로 설정한다. public Address (String street, String town, String st, long zip) { streetAddress = street; city = town; state = st; zipCode = zip; } © 2004 Pearson Addison-Wesley. All rights reserved
Address.java (Cont’d) //---------------------------------------------------------------- // 이 Address 객체의 스트링 표현을 반환한다. public String toString() { String result; result = streetAddress + "\n"; result += city + ", " + state + " " + zipCode; return result; } } © 2004 Pearson Addison-Wesley. All rights reserved
this 참조 this 참조 예제 객체에게 자신을 참조할 수 있도록 해준다. 메쏘드는 보통 특정 객체를 통해 호출되는데 tryMe 메쏘드에서 this 참조가 사용된다면: obj1.tryMe(); obj2.tryMe(); 첫 번째 호출: this 참조가 obj1을 참조하고 두 번째 호출: this 참조가 obj2를 참조한다. © 2004 Pearson Addison-Wesley. All rights reserved
this 참조 this 참조 사용 예 구성자의 매개변수들을 같은 이름을 갖는 실체 변수들로부터 구분하는데 사용된다. 구성자의 매개변수들을 같은 이름을 갖는 실체 변수들로부터 구분하는데 사용된다. 예를 들어 4장의 Account 클래스의 구성자 구성자 내에서 this는 생성된 객체를 가리킨다. public Account (Sring name, long acctNumber, double balance) { this.name = name; this.acctNumber = acctNumber; this.balance = balance; } © 2004 Pearson Addison-Wesley. All rights reserved
목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces) 열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout) © 2004 Pearson Addison-Wesley. All rights reserved
인터페이스(Interfaces) 클라이언트 Java 인터페이스 메쏘드 데이터 구현할 클래스에 대한 명세(specification) 혹은 창구(interface)를 미리 선언할 수 있다. 클래스가 구현할 메쏘드들을 추상 메쏘드 형태로 선언한다. 필요한 상수 선언도 가능하다. 메쏘드 데이터 클라이언트 © 2004 Pearson Addison-Wesley. All rights reserved
인터페이스(Interfaces) client 추상 메쏘드(abstract method) savings deposit 본체의 구현 없는 메쏘드 헤더(header) 이다. 추상 메쏘드는 abstract 조정자(modifier)를 사용 인터페이스 안의 모든 메쏘드는 추상 메쏘드이기 때문에 보통 abstract 조정자를 생략한다. client savings deposit withdraw add_interest produce_statement © 2004 Pearson Addison-Wesley. All rights reserved
interface는 예약어(reserved word) 이다. 인터페이스(Interfaces) interface는 예약어(reserved word) 이다. 인터페이스의 어떤 메쏘드도 정의되어있지 않다. (body를 갖고 있지 않다.) public interface Doable { public void doThis(); public int doThat(); public void doThis2 (float value, char ch); public boolean doTheOther (int num); } 각 메쏘드 헤더 뒤에는 세미콜론(;)이 온다. © 2004 Pearson Addison-Wesley. All rights reserved
인터페이스(Interfaces) 질문 클래스의 인터페이스 구현 인터페이스는 실체화(instantiate)될 수 있을까? 인터페이스 안의 메쏘드들의 가시성은? 클래스의 인터페이스 구현 클래스 헤더에 인터페이스 구현을 선언하고 인터페이스의 모든 메쏘드들에 대한 정의를 제공해야 한다. 정의하지 않으면 어떻게 될까? 인터페이스의 메쏘드 외에 추가적으로 다른 일반 메쏘드도 구현할 수 있다. © 2004 Pearson Addison-Wesley. All rights reserved
인터페이스(Interfaces) public class CanDo implements Doable { public void doThis () // whatever } public void doThat () // etc. implements: 예약어 Doable에 있는 모든 메쏘드 들을 정의해야 한다. © 2004 Pearson Addison-Wesley. All rights reserved
인터페이스(Interfaces) Complexity.java (국: 314쪽, 영: 310쪽) 참조 Question.java (국: 315쪽, 영: 311쪽) 참조 MiniQuiz.java (국: 317쪽, 영: 313쪽) 참조 © 2004 Pearson Addison-Wesley. All rights reserved
Complexity.java //******************************************************************* // Complexity.java 저자: 루이스와 롭터스 // 복잡도를 할당할 수 있는 객체에 대한 인터페이스 public interface Complexity { public void setComplexity (int complexity); public int getComplexity(); } © 2004 Pearson Addison-Wesley. All rights reserved
Question.java //******************************************************************* // Question.java 저자: 루이스와 롭터스 // 질문(과 그 답을) 표현한다. public class Question implements Complexity { private String question, answer; private int complexityLevel; //---------------------------------------------------------------- // 구성자: 질문의 복잡도를 기본으로 설정한다. public Question (String query, String result) { question = query; answer = result; complexityLevel = 1; } © 2004 Pearson Addison-Wesley. All rights reserved
Question.java (cont’d) //---------------------------------------------------------------- // 이 질문에 대한 복잡도 수준을 설정한다. //---------------------------------------------------------------- public void setComplexity (int level) { complexityLevel = level; } // 이 질문에 대한 복잡도 수준을 반환한다. public int getComplexity() return complexityLevel; © 2004 Pearson Addison-Wesley. All rights reserved
Question.java (cont’d) //---------------------------------------------------------------- // 질문을 반환한다. //---------------------------------------------------------------- public String getQuestion() { return question; } // 이 질문에 대한 답을 반환한다. public String getAnswer() return answer; © 2004 Pearson Addison-Wesley. All rights reserved
Question.java (cont’d) //---------------------------------------------------------------- // 후보 답이 정답과 같으면 참을 반환한다. //---------------------------------------------------------------- public boolean answerCorrect (String candidateAnswer) { return answer.equals(candidateAnswer); } // 이 질문(과 그 답)을 스트링으로 반환한다. public String toString() return question + "\n" + answer; } © 2004 Pearson Addison-Wesley. All rights reserved
MiniQuiz.java //******************************************************************* // MiniQuiz.java 저자: 루이스와 롭터스 // 인터페이스를 구현한 클래스 사용을 보인다. import java.util.Scanner; public class MiniQuiz { // 간단한 퀴즈를 제공한다. public static void main (String[] args) { Question q1, q2; String possible; Scanner scan = new Scanner (System.in); q1 = new Question ("What is the capital of Jamaica?“, "Kingston"); q1.setComplexity (4); q2 = new Question ("Which is worse, ignorance or apathy?", "I don't know and I don't care"); q2.setComplexity (10); © 2004 Pearson Addison-Wesley. All rights reserved
MiniQuiz.java (Cont’d) System.out.print (q1.getQuestion()); System.out.println (" (Level: " + q1.getComplexity() + ")"); possible = scan.nextLine(); if (q1.answerCorrect(possible)) System.out.println ("Correct"); else System.out.println ("No, the answer is " + q1.getAnswer()); System.out.println(); System.out.print (q2.getQuestion()); System.out.println (" (Level: " + q2.getComplexity() + ")"); © 2004 Pearson Addison-Wesley. All rights reserved
MiniQuiz.java (Cont’d) if (q2.answerCorrect(possible)) System.out.println ("Correct"); else System.out.println ("No, the answer is " + q2.getAnswer()); } } 출력 ====================================== What is the capital of Jamaica? (Level: 4) Kingston Correct Which is worse, ignorance or apathy? (Level: 10) apathy No. the answer is I don't know and I don't care © 2004 Pearson Addison-Wesley. All rights reserved
인터페이스(Interfaces) 한 클래스가 여러 개의 인터페이스 구현 가능 한 클래스가 여러 개의 인터페이스 구현 가능 클래스는 나열된 모든 인터페이스들의 모든 메쏘드들을 구현해야 한다. 클래스가 구현하는 모든 인터페이스들은 implements 절에 콤마로 구분해서 나열해야 한다. class ManyThings implements interface1, interface2 { // all methods of both interfaces } © 2004 Pearson Addison-Wesley. All rights reserved
Comparable 인터페이스 Java 표준 클래스 라이브러리가 제공하는 인터페이스 Comparable 인터페이스 두 개의 객체를 비교하는 compareTo 추상 메쏘드를 갖고 있다. String 클래스는 두 개의 문자열을 사전적 순서로 정렬하는데 사용할 수 있는 Comparable 인터페이스를 구현한다.(5장) 객체 비교를 위해 어떤 클래스도 Comparable을 구현할 수 있다. if (obj1.compareTo(obj2) < 0) System.out.println ("obj1 is less than obj2"); © 2004 Pearson Addison-Wesley. All rights reserved
인터페이스(Interfaces) QnA 그러면 왜? 인터페이스 꼭 사용해야 하나요? 인터페이스를 구현하지 않고서도 특정 메쏘드를 구현하는 클래스를 작성할 수 있다. 그러면 왜? 인터페이스를 구현하는 클래스들의 객체를 일관성 있게 다를 수 있다. 인터페이스는 Java의 객체지향 디자인의 중요한 요소이다. 9장에서 더 자세히… © 2004 Pearson Addison-Wesley. All rights reserved
목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces) 열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout) © 2004 Pearson Addison-Wesley. All rights reserved
열거 타입(Enumerated Types) 새로운 데이터 타입을 정의하고 그 타입의 모든 값들을 열거한다. enum Season {winter, spring, summer, fall} 일단 정의되면 다른 타입처럼 사용 가능하다. Season time; 변수 time에 할당 할 수 있는 값 enum Season 정의에 열거된 값들만을 배정할 수 있다. © 2004 Pearson Addison-Wesley. All rights reserved
열거 타입(Enumerated Types) 열거 타입은 사실은 특별한 종류의 클래스 이다. 열거 타입의 값은 사실 그 타입의 객체이다. 예, fall은 Season 타입의 객체 이름이다. 따라서 다음과 같은 배정문이 유효하다. time = Season.fall; © 2004 Pearson Addison-Wesley. All rights reserved
열거 타입(Enumerated Types) 열거 타입 정의는 단순한 값들의 나열 이상 가능 열거 타입은 클래스와 같이 추가적인 실체 데이터나 메쏘드를 더 포함할 수 있기 때문이다. 또한 enum 구성자(constructor)를 정의 할 수 있다. 열거 타입을 위해 열거되는 각 각의 값이 구성자를 호출 한다. Season.java (국: 321쪽, 영: 318쪽) SeasonTester.java (국: 322쪽, 영: 319쪽) c.f. 이 열거 타입은 Java 1.5 이상에서 지원되는 새로운 기능이다. © 2004 Pearson Addison-Wesley. All rights reserved
Season.java // ******** Season.java : Season의 값들을 나열한다. ***********************// public enum Season { winter ("December through February"), spring ("March through May"), summer ("June through August"), fall ("September through November"); private String span; //************ 구성자: 각 값에 연관된 스트링을 설정한다. **************// Season (String months) { span = months; } //************** 이 값의 span 메시지를 반환한다. ************************// public String getSpan() { return span; } © 2004 Pearson Addison-Wesley. All rights reserved
SeasonTester.java //******************************************************************* // SeasonTester.java 저자: 루이스와 롭터스 // 열거 타입의 사용을 보인다. public class SeasonTester { //---------------------------------------------------------------- // Season 열거 타입의 값에 대해서 반복한다. public static void main (String[] args) { for (Season time : Season.values()) System.out.println (time + "\t" + time.getSpan()); } } 출력 ========================= winter December through February spring March through May summer June through August fall September through November © 2004 Pearson Addison-Wesley. All rights reserved
목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces) 열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout) © 2004 Pearson Addison-Wesley. All rights reserved
메쏘드 설계 high-level 디자인의 쟁점 사항: low-level 디자인의 쟁점 사항 주요 클래스와 객체의 식별 주요 임무의 부여 low-level 디자인의 쟁점 사항 주요 메쏘드의 디자인 효과적이고 세련된 시스템 디자인이 될 수 있도록 구현해야 한다. © 2004 Pearson Addison-Wesley. All rights reserved
메쏘드 설계 알고리즘(algorithm) 어떤 문제를 해결하는 단계별 과정이다 예: 조리법이나 여행 길 안내 등도 하나의 알고리즘이다 각 메쏘드는 목적에 도달하는 방법을 결정하는 알고리즘을 구현한다 알고리즘은 흔히 코드 문장과 영어 절을 혼합한 의사코드(pseudocode)로 기술된다 © 2004 Pearson Addison-Wesley. All rights reserved
메쏘드 분해 작은 메쏘드 큰 메쏘드 메소드 전체를 하나로 간주 여러 개의 작은 메쏘드로 분해 필요 어떤 객체의 public 메쏘드는 하나 혹은 여러 개의 private 메쏘드들을 호출하기도 한다 보조 역할을 하는 메쏘드들도 필요하면 다른 보조 역할을 하는 메쏘드들을 호출할 수 있다. © 2004 Pearson Addison-Wesley. All rights reserved
메쏘드 분해 메쏘드 분해가 필요한 예를 살펴보자 피그라틴어는 가상의 언어로 단어들을 다음과 같이 변경한다. book 영어를 피그라틴(Pig Latin)어로 번역하는 프로그램 피그라틴어는 가상의 언어로 단어들을 다음과 같이 변경한다. 각 단어를 처음 음을 끝으로 이동하고 “ay ” 를 첨부하여 수정한다 모음으로 시작된 단어들은 “yay ” 를 끝에 첨부 단어 시작의 “ch”나 “st” 같은 자음은 함께 끝으로 이동하고 “ay” 첨부 예, book ookbay table abletay item itemyay chair airchay © 2004 Pearson Addison-Wesley. All rights reserved
메쏘드 분해 이 프로그램을 한 메쏘드로 작성하면 너무 복잡하다. 단어 번역의 3가지 처리 경우: 번역 메쏘드를 자연스럽게 여러 개의 작은 조각으로 분해하는 디자인이 바람직하다. 문장을 번역하는 일 3개의 경우로 분해해서 해결 단어 번역의 3가지 처리 경우: 모음으로 시작하는 경우 혼성자음 sh, cr, th, 등으로 시작하는 경우 하나의 자음으로 시작하는 경우 © 2004 Pearson Addison-Wesley. All rights reserved
메쏘드 분해 PigLatin.java (국: 324쪽, 영: 320쪽) 참조 PigLatinTranslator.java (국: 325쪽, 영: 323쪽) 참조 UML 클래스 다이어그램 변수(variable)나 메쏘드(method)의 가시성(visibility)은 특수 문자를 사용하여 표현할 수 있다. Public 멤버는 플러스기호(plus sign: + )로 표시 Private 멤버는 마이너스기호(minus sign: - )로 표시 © 2004 Pearson Addison-Wesley. All rights reserved
PigLatin 프로그램을 위한 UML 다이어그램 + main (args : String[]) : void + translate (sentence : String) : String - translateWord (word : String) : String - beginsWithVowel (word : String) : boolean - beginsWithBlend (word : String) : boolean PigLatinTranslator © 2004 Pearson Addison-Wesley. All rights reserved
PigLatin.java //******************************************************************* // PigLatin.java Author: Lewis/Loftus // 메쏘드 분해 개념을 보인다. import java.util.Scanner; public class PigLatin { //---------------------------------------------------------------- // 문장을 읽어 피그라틴어로 번역한다. public static void main (String[] args) { String sentence, result, another; Scanner scan = Scanner.create (System.in); © 2004 Pearson Addison-Wesley. All rights reserved
PigLatin.java (cont’d) do { System.out.println (); System.out.println ("Enter a sentence (no punctuation):"); sentence = scan.nextLine(); result = PigLatinTranslator.translate (sentence); System.out.println ("That sentence in Pig Latin is:"); System.out.println (result); System.out.print ("Translate another sentence (y/n)? "); another = scan.nextLine(); } while (another.equalsIgnoreCase("y")); } } © 2004 Pearson Addison-Wesley. All rights reserved
PigLatin.java (cont’d) 출력 ===================================== Enter a sentence (on punctuation): Do you speak Pig Latin That sentence in Pig Latin is: Oday ouyay eskspay igpay atinlay Translate another sentence(y/n)? y Enter a sentence (no punctuation): Play it again Sam ayplay ityay againyay amsay Translate another sentence (y/n)? n © 2004 Pearson Addison-Wesley. All rights reserved
PigLatinTranslator.java //******************************************************************* // PigLatinTranslator.java 저자: 루이스와 롭터스// // 영어를 피그라틴어로 번역하는 시스템을 표현한다. // 메쏘드 분리와 StringTokenizer의 사용을 보여 준다 import java.util.Scanner; public class PigLatinTranslator { //---------------------------------------------------------------- // 단어들로 이루어진 한 문장을 피그라틴어로 번역한다. //---------------------------------------------------------------- public String translate (String sentence) { String result = ""; © 2004 Pearson Addison-Wesley. All rights reserved
PigLatinTranslator.java (Cont’d) Scanner scan = Scanner.create(sentence); sentence = sentence.toLowerCase(); while (scan.hasNext()) { result += translateWord (scan.next()); result += " "; } return result; } //---------------------------------------------------------------- // 한 단어를 피그라틴어로 번역한다. 단어가 모음으로 시작하면 단어에 접미사 "yay" // 를 붙이고 아니면 첫 번째나 두 번째 문자를 단어 제일 뒤로 옮기고 "ay"를 붙인다. //---------------------------------------------------------------- private String translateWord (String word) { String result = ""; © 2004 Pearson Addison-Wesley. All rights reserved
PigLatinTranslator.java (Cont’d) if (beginsWithVowel(word)) result = word + "yay"; else if (beginsWithBlend(word)) result = word.substring(2) + word.substring(0,2) + "ay"; else result = word.substring(1) + word.charAt(0) + "ay"; return result; } //---------------------------------------------------------------- // 명시된 단어가 모음으로 시작하는지 결정한다. //---------------------------------------------------------------- private boolean beginsWithVowel (String word) { String vowels = "aeiouAEIOU"; char letter = word.charAt(0); return (vowels.indexOf(letter) != -1); © 2004 Pearson Addison-Wesley. All rights reserved
PigLatinTranslator.java (Cont’d) // 명시된 단어가 특정 두 문자의 접두사로 시작하는지 결정한다. // private boolean beginsWithBlend (String word) { return ( word.startsWith ("bl") || word.startsWith ("sc") || word.startsWith ("br") || word.startsWith ("sh") || word.startsWith ("ch") || word.startsWith ("sk") || word.startsWith ("cl") || word.startsWith ("sl") || word.startsWith ("cr") || word.startsWith ("sn") || word.startsWith ("dr") || word.startsWith ("sm") || word.startsWith ("dw") || word.startsWith ("sp") || word.startsWith ("fl") || word.startsWith ("sq") || word.startsWith ("fr") || word.startsWith ("st") || word.startsWith ("gl") || word.startsWith ("sw") || word.startsWith ("gr") || word.startsWith ("th") || word.startsWith ("kl") || word.startsWith ("tr") || word.startsWith ("ph") || word.startsWith ("tw") || word.startsWith ("pl") || word.startsWith ("wh") || word.startsWith ("pr") || word.startsWith ("wr") ); } } © 2004 Pearson Addison-Wesley. All rights reserved
Java에서 매개 변수 전달 메쏘드가 호출될 때 실 매개변수(actual arguments) 값은 형식 매개변수에 복사된다 char calc (int num1, int num2, String message) { int sum = num1 + num2; char result = message.charAt (sum); return result; } ch = obj.calc (25, count, "Hello"); 실 매개변수(actual parameters) 형식 매개변수(fomal parameters) © 2004 Pearson Addison-Wesley. All rights reserved
Java에서 매개 변수 전달 기초 타입 전달 객체 참조 전달 값 전달(pass by value) 값이 복사되어 전달된다. 참조 전달(pass by reference) 형식 매개변수는 실 매개변수와 이명이 되며 형식 매개변수와 실 매개변수는 같은 객체를 참조한다. © 2004 Pearson Addison-Wesley. All rights reserved
객체 매개변수 전달 매개변수를 받은 메쏘드 ParameterTester.java (국: 329쪽, 영: 327쪽) 참조 메쏘드 밖에 영향을 줄 수도 있고 혹은 안 줄 수도 있다 참조를 사용할 경우 메쏘드 밖에도 영향을 줄 수 있다. ParameterTester.java (국: 329쪽, 영: 327쪽) 참조 ParameterModifier.java (국: 330쪽, 영: 329쪽) 참조 Num.java (국: 331쪽, 영: 330쪽) 참조 객체의 내부 상태(state)를 변화시킬 때와 참조되는 객체를 변화시킬 때의 차이를 유의하여 보자 © 2004 Pearson Addison-Wesley. All rights reserved
ParameterTester.java //******************************************************************* // ParameterTester.java 저자: 루이스와 롭터스 // 다양한 타입의 매개변수 전달 효과를 보인다. class ParameterTester { //---------------------------------------------------------------- // changeValues 메쏘드에 실 매개변수로 사용될 3개의 변수들(하나는 기본타입, // 두 개는 객체들)을 설정한다. 메쏘드 호출 전과 호출 후 값을 인쇄한다. //---------------------------------------------------------------- public static void main (String[] args) { ParameterModifier modifier = new ParameterModifier(); int a1 = 111; Num a2 = new Num (222); Num a3 = new Num (333); © 2004 Pearson Addison-Wesley. All rights reserved
ParameterTester.java (cont’d) System.out.println ("Before calling changeValues:"); System.out.println ("a1\ta2\ta3"); System.out.println (a1 + "\t" + a2 + "\t" + a3 + "\n"); modifier.changeValues (a1, a2, a3); System.out.println ("After calling changeValues:"); } } 출력: ===================== Before calling changeValues: a1 a2 a3 111 222 333 Before changing the values: f1 f2 f3 After changing the values: f1 f2 f3 999 888 777 After calling changeValues: 111 888 333 © 2004 Pearson Addison-Wesley. All rights reserved
ParameterModifier.java // ParameterModifier.java // 다양한 타입의 매개변수 전달 효과를 보인다. class ParameterModifier { // 변경 전과 변경 후의 값을 인쇄하면서 매개 변수를 변경한다. public void changeValues (int f1, Num f2, Num f3) { System.out.println ("Before changing the values:"); System.out.println ("f1\tf2\tf3"); System.out.println (f1 + "\t" + f2 + "\t" + f3 + "\n"); f1 = 999; f2.setValue(888); f3 = new Num (777); System.out.println ("After changing the values:"); } } © 2004 Pearson Addison-Wesley. All rights reserved
Num.java class Num { private int value; { value = update; } //******************************************************************* // Num.java // 하나의 정수를 객체로 표현한다. class Num { private int value; // 초기값을 저장하여 Num 객체를 설정한다. public Num (int update) { value = update; } // 새로 명시된 값으로 저장된 값을 설정한다. public void setValue (int update) // 저장된 정수 값을 문자열로 반환한다. public String toString () { return value + ""; } } © 2004 Pearson Addison-Wesley. All rights reserved
메쏘드 중복정의(Overloading) 메쏘드 중복정의(Method overloading) 같은 메쏘드 이름으로 여러 개의 메쏘드를 정의하는 것이다. QnA 그러면 메쏘드가 호출될 때 어떻게 중복정의된 메쏘드들을 구별할 수 있나요? 메쏘드 이름만으로는 어느 메쏘드를 호출할 지 결정할 수 없다. 메쏘드의 시그너처(signature) 중복정의되는 메쏘드의 시그너처는 반드시 달라야 한다. 메쏘드 이름, 매개변수의 수, 각 매개변수의 타입 및 순서 © 2004 Pearson Addison-Wesley. All rights reserved
메쏘드 중복정의(Overloading) 컴파일러는 매개변수를 분석하여 어느 메쏘드가 호출되어야 할지 결정한다. float tryMe(int x) { return x + .375; } result = tryMe(25, 4.32) 호출(Invocation) float tryMe(int x, float y) { return x*y; } © 2004 Pearson Addison-Wesley. All rights reserved
메쏘드 중복정의(Overloading) println 메쏘드의 중복정의: println (String s) println (int i) println (double d) ... 다음 명령문들은 각기 다른 버전의 println 메쏘드를 호출 한다: System.out.println ("The total is:"); System.out.println (total); © 2004 Pearson Addison-Wesley. All rights reserved
메쏘드 중복정의(Overloading) 메쏘드의 반환 타입(return type) 메쏘드의 시그너처 에 포함되지 않는다 ! 따라서 중복정의 된 메쏘드는 반환 타입만 달라서는 안된다. 메쏘드 호출에는 반환타입이 직접적으로 명시되지 않는다 구성자(Constructor)도 중복정의 가능 구성자를 중복정의 함으로써 객체를 초기화하고 생성하는 다양한 방법을 제공한다 © 2004 Pearson Addison-Wesley. All rights reserved
목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces) 열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout) © 2004 Pearson Addison-Wesley. All rights reserved
테스트(Testing) 테스트(Testing) 어떤 평가는 코드작성 전에 이루어져야 한다 완성된 프로그램을 다양한 입력으로 실행시키는 것 혹은 개발 중인 시스템의 질을 판단하기 위해서 인간이나 기계에 의해서 수행되는 다양한 평가들을 포함한다. 어떤 평가는 코드작성 전에 이루어져야 한다 문제를 빠른 시점에 찾아 낼 수록 고치기 쉽고 비용도 싸다. © 2004 Pearson Addison-Wesley. All rights reserved
테스트(Testing) 테스트 왜 중요한가? 테스트 왜 어려운가? 테스트 예 테스트의 목적은 오류(error)를 찾아내는 것이다 오류를 찾아 고침으로서 프로그램의 품질을 높여나가게 된다 테스트 왜 어려운가? 그러나 오류가 모두 제거되었다고 확신할 수 없다 테스트 예 두 개의 정수를 입력으로 받아 어떤 결과를 출력하는 프로그램의 테스트 모든 정수 쌍에 대해서 테스트 할 수 있을까? © 2004 Pearson Addison-Wesley. All rights reserved
테스트(Testing) 그럼 언제 까지 테스트를 해야 할 것인가? 개념적인 답: 영원히 계속 궁색한 답: 시간이 되는 동안 개념적인 답: 영원히 계속 궁색한 답: 시간이 되는 동안 보다 낳은 답: 발견하지 못한 오류에 대한 위험을 스스로 부담할 의사가 생길 때 까지 © 2004 Pearson Addison-Wesley. All rights reserved
재검토(Reviews) 재검토(review) 설계나 코드를 다른 사람에게 제공하는 것은: 여러 사람들이 설계 문서나 코드를 주의 깊게 검토하는 것 일반적이고 효과적인 인간중심(human-based)의 테스트이다 종종 검사(inspection) 혹은 워크쓰루(walkthrough)라고 한다. 설계나 코드를 다른 사람에게 제공하는 것은: 스스로 보다 신중하게 생각하도록 만들고 다른 사람들의 관점을 들어볼 수 있도록 한다. © 2004 Pearson Addison-Wesley. All rights reserved
테스트 케이스(Test Cases) 테스트 케이스(test case) 중대형의 시스템의 테스트 입력, 사용자의 행동, 혹은 다른 초기 조건과 예상된 출력들의 집합이다 형식에 맞추어 편성하여 완전한 테스트 모음(test suite)을 만든다 중대형의 시스템의 테스트 반드시 조심스럽게 관리되고 처리되어야 한다 여러 기관에서는 테스트를 전담하기 위한 독립적인 품질 보장 부서(Quality Assurance (QA) department) 따로 두고 있다 © 2004 Pearson Addison-Wesley. All rights reserved
결함 테스트와 회귀 테스트 결함 테스트(Defect testing) 회귀 테스트(regression testing) 테스트 케이스들의 실행을 통해 발견 못한 오류를 찾아내는 테스트 모든 가능한 입력과 사용자의 행위를 위한 테스트 케이스를 만들어 내는 것은 불가능하다. 문제를 최대한 찾아낼 수 있도록 테스트들을 디자인 해야 한다. 회귀 테스트(regression testing) 오류를 수정하는 행위가 새로운 오류를 발생시킬 수 있다. 오류들의 수정 후에는 회귀 테스트를 해서 이전 수행했던 테스트가 새로운 오류를 발생하지 않는지 검사 © 2004 Pearson Addison-Wesley. All rights reserved
Black-Box 테스트 black-box 테스트 좋은 테스트 모음(test suite) 내부 로직(logic)의 고려 없이 테스트 케이스를 개발한다 입력과 그에 기대되는 출력에 기반을 둔다 입력은 동치 유형(equivalence category)으로 모아 재구성 같은 동치 유형에 있는 두 개의 입력 값은 유사한 출력을 생성해 낼 것이다 좋은 테스트 모음(test suite) 모든 동치 유형(equivalence category)을 포함하고 각 유형 사이의 경계도 검증할 수 있어야 한다 © 2004 Pearson Addison-Wesley. All rights reserved
White-Box 테스트 White-box 테스트 코드의 실행 경로 좋은 테스트 코드의 내부 구조와 구현의 검사에 중점을 두고 있다 목적은 프로그램의 모든 실행 경로가 적어도 한 번은 테스트됨을 확인하는 것이다 코드의 실행 경로 프로그램에 있는 조건문과 반복문의 지배를 받게 된다 좋은 테스트 black-box와 white-box 테스트 모두를 포함하는 것이다 © 2004 Pearson Addison-Wesley. All rights reserved
목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces) 열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout) © 2004 Pearson Addison-Wesley. All rights reserved
GUI 설계 소프트웨어의 목적이 사용자의 문제 해결을 돕는 것이라는 것을 항상 기억해야 한다 소프트웨어의 목적이 사용자의 문제 해결을 돕는 것이라는 것을 항상 기억해야 한다 그 목적을 위하여, GUI 설계자는: 사용자를 파악하고 사용자의 실수를 예방하고 사용자의 능력을 최대로 활용하고 일관성을 가져야 한다. 각각에 대해 좀더 자세히 보도록 하자 © 2004 Pearson Addison-Wesley. All rights reserved
사용자 파악 사용자 파악을 위해 다음을 이해해야 한다: 사용자 인터페이스(user interface) 사용자가 진정 요구하는 것 사용자의 일반적 행동 컴퓨터처리와 문제에 관련된 전문지식 정도 사용자 인터페이스(user interface) 사용자에게는 인터페이스도 단지 하나의 프로그램이다. 사용자의 실수가 최소화 되도록 설계되어야 한다 © 2004 Pearson Addison-Wesley. All rights reserved
사용자 능력의 최대활용 모든 사용자가 다 같지는 않다. 적절하다면 하나의 일을 하는데 여러 방법을 제공 어떤 사용자가 다른 사용자에 비해 더 시스템에 익숙할 수 있다. 정통한 사용자를 종종 파워유저(power user)라 한다 적절하다면 하나의 일을 하는데 여러 방법을 제공 "wizards"를 제공하여 처리과정을 사용자가 자동으로 순차적으로 진행할 수 있게 하거나 파워유저를 위해서는 단축키(short cut)를 제공 방해가 되지 않는 범위에서 도움말 제공 © 2004 Pearson Addison-Wesley. All rights reserved
일관성 유지 일관성은 중요하다 – 사용자는 어떤 것의 모양이나 일하는 방식 등에 쉽게 익숙해지게 된다 일관성은 중요하다 – 사용자는 어떤 것의 모양이나 일하는 방식 등에 쉽게 익숙해지게 된다 색상도 유사한 정보나 처리를 나타내기 위해 일관성을 가져야 한다 화면 배치도 시스템의 각 부분에 있어서 일관성을 유지해야 한다. 예를 들면, 에러 메시지도 항상 같은 위치에 나타나도록 해야 한다 © 2004 Pearson Addison-Wesley. All rights reserved
레이아웃 관리자(Layout Manager) 컨테이너 내에서 컴포넌트들의 배치를 제어하는 객체이다. 각 컨테이너는 초기 설정된 레이아웃 관리자를 갖고 있고 필요하면 명시적으로 다른 것으로 대치할 수 있다. Java 표준 라이브러리가 제공하는 레이아웃 관리자: Flow Layout Border Layout Card Layout Grid Layout GridBag Layout AWT에 정의 Box Layout Overlay Layout Swing에 정의 © 2004 Pearson Addison-Wesley. All rights reserved
레이아웃 관리자(Layout Manager) 레이아웃 관리자 변경 컨테이너의 setLayout 메쏘드를 사용 JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); 예제 프로그램 꼬리표 페인(tabbed pane)의 사용을 소개 사용자가 여러 페인들 중 현재 보이는 것을 선택할 수 있게 하는 컨테이너이다. LayoutDemo.java (국: 341쪽, 영: 340쪽) 참조 IntroPanel.java (국: 342쪽, 영: 341쪽) 참조 © 2004 Pearson Addison-Wesley. All rights reserved
LayoutDemo.java //******************************************************************** // LayoutDemo.java 저자: Lewis/Loftus // 흐름, 영역, 격자, 그리고 상자 레이아웃의 사용을 보여준다. import javax.swing.*; public class LayoutDemo { //----------------------------------------------------------------- // 꼬리표 페인을 포함하고 있는 프레임을 준비한다. // 각각의 꼬리표가 붙은 페인은 상이한 레이아웃 관리자를 보여준다. public static void main (String[] args) JFrame frame = new JFrame ("Layout Manager Demo"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); © 2004 Pearson Addison-Wesley. All rights reserved
LayoutDemo.java (cont’d) JTabbedPane tp = new JTabbedPane(); tp.addTab ("Intro", new IntroPanel()); tp.addTab ("Flow", new FlowPanel()); tp.addTab ("Border", new BorderPanel()); tp.addTab ("Grid", new GridPanel()); tp.addTab ("Box", new BoxPanel()); frame.getContentPane().add(tp); frame.pack(); frame.setVisible(true); } © 2004 Pearson Addison-Wesley. All rights reserved
IntroPanel.java //******************************************************************** // IntroPanel.java 저자: Lewis/Loftus // LayoutDemo 프로그램을 위한 소개 패널을 나타낸다 import java.awt.*; import javax.swing.*; public class IntroPanel extends JPanel { //************* 두 개의 레이블을 가진 패널을 준비한다. ***************// public IntroPanel() setBackground (Color.green); JLabel l1 = new JLabel ("Layout Manager Demonstration"); JLabel l2 = new JLabel ("Choose a tab to see an example of " + "a layout manager."); add (l1); add (l2); } © 2004 Pearson Addison-Wesley. All rights reserved
흐름 레이아웃(Flow Layout) 흐름 레이아웃(Flow layout) 구체적으로 컴포넌트들을 한 행(row)에 배치하고 그 행이 다하면 다음 행에 배치한다. 구체적으로 컨테이너에 더해진 모든 컴포넌트들을 놓기에 필요한 만큼 행이 추가 된다. 컴포넌트들은 컨테이너에 더해진 순서대로 디스플레이 된다 컴포넌트는 윈도우 내에서 가운데정렬로 초기화 되어있다. 그러나 좌측정렬이나 우측정렬도 가능하다 컴포넌트들 사이의 수평간격(horizontal gap)과 수직 간격(vertical gap) 도 명시적으로 설정할 수 있다. FlowPanel.java (국: 344쪽, 영: 343쪽) 참조 © 2004 Pearson Addison-Wesley. All rights reserved
FlowPanel.java import java.awt.*; import javax.swing.*; //******************************************************************** // FlowPanel.java 저자: Lewis/Loftus / // // LayoutDemo 프로그램에서 흐름 레이아웃 관리자를 보여주는 패널을 나타낸다 //******************************************************************** import java.awt.*; import javax.swing.*; public class FlowPanel extends JPanel { //----------------------------------------------------------------- // 흐름 레이아웃이 위치에 어떻게 영향을 미치는지 보이도록, // 몇 개의 버튼들을 가진 패널을 준비한다. public FlowPanel () setLayout (new FlowLayout()); setBackground (Color.green); © 2004 Pearson Addison-Wesley. All rights reserved
FlowPanel.java (cont’d) JButton b1 = new JButton ("BUTTON 1"); JButton b2 = new JButton ("BUTTON 2"); JButton b3 = new JButton ("BUTTON 3"); JButton b4 = new JButton ("BUTTON 4"); JButton b5 = new JButton ("BUTTON 5"); add (b1); add (b2); add (b3); add (b4); add (b5); } © 2004 Pearson Addison-Wesley. All rights reserved
영역 레이아웃(Border Layout) 컴포넌트가 추가될 수 있는 5개의 영역을 정의하고 있다 각 영역은 하나의 컴포넌트를 디스플레이 할 수 있다. BorderPanel.java (국: 347쪽, 영: 346쪽) 참조 North South Center East West © 2004 Pearson Addison-Wesley. All rights reserved
BorderPanel.java import java.awt.*; import javax.swing.*; //******************************************************************** // BorderPanel.java 저자: Lewis/Loftus // // LayoutDemo 프로그램에서 영역 레이아웃 관리자를 보여주는 // 패널을 나타낸다. import java.awt.*; import javax.swing.*; public class BorderPanel extends JPanel { //----------------------------------------------------------------- // 영역 레이아웃이 위치, 모양, 그리고 크기에 어떻게 영향을 미치는지 보이도록, // 영역 레이아웃의 각 영역에 하나의 버튼을 가진 패널을 준비한다. public BorderPanel() © 2004 Pearson Addison-Wesley. All rights reserved
BorderPanel.java (cont’d) setLayout (new BorderLayout()); setBackground (Color.green); JButton b1 = new JButton ("BUTTON 1"); JButton b2 = new JButton ("BUTTON 2"); JButton b3 = new JButton ("BUTTON 3"); JButton b4 = new JButton ("BUTTON 4"); JButton b5 = new JButton ("BUTTON 5"); add (b1, BorderLayout.CENTER); add (b2, BorderLayout.NORTH); add (b3, BorderLayout.SOUTH); add (b4, BorderLayout.EAST); add (b5, BorderLayout.WEST); } © 2004 Pearson Addison-Wesley. All rights reserved
격자 레이아웃(Grid Layout) 격자 레이아웃(grid layout) 배치 순서 행과 열의 직사각형 격자에 컨테이너의 컴포넌트들을 배치한다 하나의 컴포넌트는 격자의 하나의 칸(cell)에 놓여지며, 모든 칸들은 동일한 크기를 갖는다. 배치 순서 컴포넌트가 추가 될 때 마다 왼쪽에서 오른쪽으로 또 위에서 아래로 격자를 채워나가도록 초기화 되어 있 GridPanel.java (국: 349쪽, 영: 349쪽) 참조 © 2004 Pearson Addison-Wesley. All rights reserved
GridPanel.java //******************************************************************** // GridPanel.java 저자: Lewis/Loftus // LayoutDemo 프로그램에서 격자 레이아웃 관리자를 // 보여주는 패널을 나타낸다. import java.awt.*; import javax.swing.*; public class GridPanel extends JPanel { //----------------------------------------------------------------- // 격자 레이아웃이 위치, 모양, 크기에 어떻게 영향을 미치는지 보이도록, // 몇 개의 버튼들을 가진 패널을 준비한다. public GridPanel() © 2004 Pearson Addison-Wesley. All rights reserved
GridPanel.java (cont’d) setLayout (new GridLayout (2, 3)); setBackground (Color.green); JButton b1 = new JButton ("BUTTON 1"); JButton b2 = new JButton ("BUTTON 2"); JButton b3 = new JButton ("BUTTON 3"); JButton b4 = new JButton ("BUTTON 4"); JButton b5 = new JButton ("BUTTON 5"); add (b1); add (b2); add (b3); add (b4); add (b5); } © 2004 Pearson Addison-Wesley. All rights reserved
상자 레이아웃(Box Layout) 상자 레이아웃(box layout) 컴포넌트들을 하나의 행 또는 하나의 열에 수평 또는 수직으로 조직한다. 컴포넌트들은 컨테이너에 추가될 때 마다 위에서 아래로 혹은 왼쪽에서 오른쪽으로 배치된다 상자 레이아웃을 사용하는 여러 개의 컨테이너를 결합하여 여러 가지 다른 배치를 만들어낼 수 있다 © 2004 Pearson Addison-Wesley. All rights reserved
상자 레이아웃(Box Layout) 투명 컴포넌트(Invisible components) 두 종류의 투명 컴포넌트가 있다. 컴포넌트들 사이에 공간을 만들기 위해 상자 레이아웃 컨테이너에 더해질 수 있다. 두 종류의 투명 컴포넌트가 있다. 고정 범위(Rigid areas): 고정된 크기를 가짐 고정 범위는 Box 클래스의 createRigidArea 메쏘드를 사용하여 생성된다 부착 범위(Glue): 공간이 필요한 곳을 지정 부착 범위는 createHorizontalGlue 메쏘드나 createVerticalGlue 메쏘드를 사용하여 생성한다 See BoxPanel.java (국: 352쪽, 영: 352 쪽) 참조 © 2004 Pearson Addison-Wesley. All rights reserved
BoxPanel.java //******************************************************************** // BoxPanel.java 저자: Lewis/Loftus // // LayoutDemo 프로그램에서 상자 레이아웃 관리자를 보여주는 패널을 나타낸다. import javax.awt.*; import javax.swing.*; public class BoxPanel extends JPanel { // 수직적 상자 레이아웃(과 투명 컴포넌트들)이 위치에 어떻게 영향을 미치는 // 보이도록, 몇 개의 버튼들을 가진 패널을 준비한다. public BoxPanel() { setLayout (new BoxLayout (this, BoxLayout.Y_AXIS)); setBackground (Color.green); © 2004 Pearson Addison-Wesley. All rights reserved
JButton b1 = new JButton ("BUTTON 1"); add (b1); add (Box.createRigidArea (new Dimension (0, 10))); add (b2); add (Box.createVerticalGlue()); add (b3); add (b4); add (Box.createRigidArea (new Dimension (0, 20))); add (b5); } } © 2004 Pearson Addison-Wesley. All rights reserved
요약 6장에서 살펴 본 주요 내용: 소프트웨어 개발 과정 프로그램에 필요한 클래스와 객체의 결정 클래스 사이의 관계 static 조정자(static modifier) 인터페이스 작성 열거 타입(enumerated type) 클래스의 디자인 메쏘드 설계와 메쏘드 중복정의 GUI 설계와 레이아웃 관리자(layout managers) © 2004 Pearson Addison-Wesley. All rights reserved