Presentation is loading. Please wait.

Presentation is loading. Please wait.

객체 지향 설계 Object-Oriented Design

Similar presentations


Presentation on theme: "객체 지향 설계 Object-Oriented Design"— Presentation transcript:

1 객체 지향 설계 Object-Oriented Design
6 장 객체 지향 설계 Object-Oriented Design

2 객체지향 설계 이 장에서는 클래스와 객체의 설계 방법에 대해 알아본다. 6장의 주요 내용: 소프트웨어 개발 과정
이 장에서는 클래스와 객체의 설계 방법에 대해 알아본다. 6장의 주요 내용: 소프트웨어 개발 과정 프로그램에 필요한 클래스와 객체의 결정 클래스 사이의 관계 static 조정자(static modifier) 인터페이스 작성 열거 타입(enumerated type) 클래스의 설계 메쏘드 설계와 메쏘드 중복정의 GUI 설계와 레이아웃 관리자(layout managers)

3 목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces)
열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout)

4 프로그램 개발 소프트웨어 개발을 위한 4가지 기본 활동: 위의 개발활동은 순차적이지 않고 단계가 중복되거나 상호작용 된다.
요구사항의 확립 (establishing the requirements) 설계 (creating a design) 코드 개발 (implementing the code) 프로그램 테스트 (testing the implementation) 위의 개발활동은 순차적이지 않고 단계가 중복되거나 상호작용 된다.

5 요구사항 소프트웨어 요구사항은 프로그램이 하고자 하는 일들을 명시하는 것이다.
소프트웨어 요구사항은 프로그램이 하고자 하는 일들을 명시하는 것이다. 어떻게 할 것인가가 아닌 무엇을 할 것인가 대체로 초기 요구사항이 제공된다. 그러나 초기 요구사항은 불완전하기 때문에 신중히 분석되고 확장되어 다듬어져야 된다. 자세하고 명료하며 완전한 요구사항을 규정하는 것은 힘든 일이다. 요구사항에 대한 세심한 주의가 전체 프로젝트에 대한 시간과 비용을 현저히 줄일 수 있다.

6 설계(Design) 소프트웨어 설계는 소프트웨어의 요구사항을 어떻게 달성할지 나타내는 것이다. 소프트웨어 설계 시 결정 사항:
어떻게 해답을 관리 가능한 작은 모듈들로 나눌 것인가? 각각의 모듈들은 무엇을 할 것인가? 객체지향 설계는 프로그램에 필요한 클래스와 객체들을 명시하고 그들이 어떻게 상호작용 하는지 결정한다. 저 수준 설계에서는 각 메쏘드가 일을 수행하는 방법도 포함한다.

7 구현 구현은 설계내용을 소스 코드로 작성하는 과정이다.
많은 초보 프로그래머는 코드 작성을 소프트웨어 개발의 핵심으로 생각하고 있는데 사실 코딩은 가장 덜 창조적인 작업이다. 대부분의 중요한 결정은 요구사항을 결정하고 설계를 수행하는 단계에서 하게 된다. 구현은 스타일 가이드라인과 소프트웨어 설명서를 포함하는 상세한 코딩에 초점을 맞추고 있다.

8 테스트 테스트는 프로그램이 수행될 주어진 모든 제약 조건 하에서 의도한 문제를 제대로 해결하는지 확인하는 작업이다.
테스트는 프로그램이 수행될 주어진 모든 제약 조건 하에서 의도한 문제를 제대로 해결하는지 확인하는 작업이다. 프로그램은 (논리적) 오류를 찾기 위해 철저히 테스트되어야 한다. 디버깅(Debugging)은 문제의 원인을 찾고 올바르게 고치는 작업이다. 테스트의 자세한 내용은 이 장의 뒷부분에서 다시 다루도록 한다.

9 목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces)
열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout)

10 클래스와 객체의 식별 객체지향 설계 이전의 전통적 프로그램은 입력 데이터에서 출력 데이터를 만들어가는 계산 과정을 강조하였다.
객체지향 설계 이전의 전통적 프로그램은 입력 데이터에서 출력 데이터를 만들어가는 계산 과정을 강조하였다. 설계과정에서 프로그램은 작은 모듈, 함수, 프로시저 등으로 분할되며 이들의 역할도 입력 데이터에서 출력 결과를 계산하는 것으로 파악할 수 있다. 입력 프로그램 출력 x, y 모듈 z = f(x,y) z

11 클래스와 객체의 식별 객체지향 설계의 핵심 활동은 해답을 만드는 클래스와 객체들을 결정하는 작업이다.
객체지향 설계의 핵심 활동은 해답을 만드는 클래스와 객체들을 결정하는 작업이다. 클래스들은 클래스 라이브러리에 있는 것이거나 이전 프로젝트에서 만들었던 것을 다시 사용하거나 혹은 새로 작성된다. 잠재적인 클래스를 식별하는 한 방법은 프로그램 요구사항에서 논의된 객체들을 식별하는 것이다. 객체는 일반적으로 명사이고 객체가 제공하는 서비스는 일반적으로 동사이다.

12 클래스와 객체의 식별 문제 명세의 일부: 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. 물론 문제 명세에서 모든 명사들이 프로그램의 클래스나 객체에 해당하는 것은 아니다.

13 클래스와 객체의 식별 클래스는 비슷한 행동을 하는 객체들의 그룹을 표현한다는 것을 기억하자.
클래스는 비슷한 행동을 하는 객체들의 그룹을 표현한다는 것을 기억하자. 일반적으로, 객체를 나타내는 클래스는 단수 명사로 이름이 주어진다. 예: Coin, Student, Message 클래스는 객체의 개념을 표현한다. 필요한 만큼의 객체를 메모리가 허용하는 범위 안에서 제한 없이 생성할 수 있다.

14 클래스와 객체의 식별 어떤 것을 클래스로 나타내야 할지 결정하는 것은 경우에 따라 어려운 일일 수 있다.
어떤 것을 클래스로 나타내야 할지 결정하는 것은 경우에 따라 어려운 일일 수 있다. 예를 들어 고용인의 주소는 실체 변수(instance variable)들의 집합으로 표현할 수도 있고 혹은 Address 객체로 나타낼 수 있다. 문제를 보다 자세하게 검토할수록 어떤 것을 클래스로 나타내고 어떤 것을 실체 변수로 나타내야 하는지 더욱 명확해 질 것이다. 어떤 클래스가 너무 복잡해지면 보통 더 작은 여러 개의 클래스로 나누어 책임을 분산하도록 설계하는 것이 좋다.

15 클래스와 객체의 식별 클래스는 필요한 만큼의 자세한 내용이 정의되어야 한다.
예를 들어 집에 있는 모든 기구들에 대해서 별개의 클래스를 생성하는 것은 설계를 불필요하게 복잡하게 만들 수 있다. 어떤 타입의 기구인지를 나타내는 실체 데이터를 갖는 하나의 Appliance 클래스로 충분할 수 있다. 어떻게 설계해야 하는가는 소프트웨어가 성취하고자 하는 것이 구체적으로 무엇이냐에 따라 다를 것이다.

16 클래스와 객체의 식별 프로그램에 필요한 클래스를 식별하는 과정의 일부분으로 각 클래스에 대한 책임 할당이 있을 수 있다.
프로그램에 필요한 클래스를 식별하는 과정의 일부분으로 각 클래스에 대한 책임 할당이 있을 수 있다. 프로그램이 수행해야 할 각각의 활동은 하나 혹은 여러 개의 클래스의 하나 혹은 여러 개의 메쏘드들에 의해 표현되어야 한다. 클래스의 행동은 프로그램의 기능을 구성하는 활동을 수행한다. 따라서 일반적으로 행동과 이를 수행하는 메쏘드의 이름에 동사를 사용한다. 설계의 초기 단계에서 클래스가 갖는 모든 메쏘드들을 식별할 필요는 없다. 주요 책임을 할당하고 이러한 책임을 어떻게 특정 메쏘드로 번역할지 고려하는 것으로 충분하다.

17 목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces)
열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout)

18 정적 클래스 멤버 정적 메쏘드(static method)는 클래스 이름을 통해 호출된다.
예, Math 클래스의 메쏘드들은 정적 메쏘드 이다: result = Math.sqrt(25) 변수도 정적일 수 있다. 메쏘드나 변수를 정적으로 만들 것인가를 결정하는 것은 프로그램 설계에 있어 중요한 결정이 된다.

19 static 조정자 (static Modifier)
예, static int count; <- 정적 변수 public static int counter (int num) <- 정적 메쏘드 정적 메쏘드와 정적 변수는 메쏘드와 변수를 클래스의 객체가 아닌 클래스 자체에 연계된다. 정적 메쏘드를 때로는 클래스 메쏘드 (class method)라 부르고 마찬가지로 정적 변수는 클래스 변수 (class variable)라 부른다.

20 정적 변수 실체 변수: 각 객체 별로 별도의 기억공간 가짐
실체 변수: 각 객체 별로 별도의 기억공간 가짐 정적 변수 : 클래스의 모든 객체들에 대해 단지 하나의 복사본이 존재. (클래스의 모든 객체들이 공유) private static float price; 정적 변수를 위한 기억 공간은 그것을 포함하는 클래스가 프로그램에서 처음으로 참조될 때 만들어진다. 그 클래스로부터 실체화 되는 모든 객체는 정적 변수를 공유한다. 따라서, 한 객체 내에서 정적 변수의 값을 변경하는 것은 다른 모든 객체의 것을 바꾸게 된다. 예: 학생 객체들을 위한 마지막 일련 번호

21 정적 메쏘드 class Helper { public static int cube (int num)
return num * num * num; } cube 메쏘드는 정적 메쏘드이기 때문에 다음과 같이 호출 된다. value = Helper.cube(5); 클래스 이름 메쏘드 이름

22 정적 클래스 멤버(Static Class Member)
조정자(modifier)의 순서는 바뀔 수 있으나 통상적으로 가시성(visibility) 조정자를 가장 먼저 쓴다. 이미 알고 있듯이 main 메쏘드는 정적 메쏘드이다. – 따라서 객체의 생성 없이 Java 인터프리터로부터 직접 호출된다. 정적 메쏘드는 실체 변수를 참조할 수 없다. 이유: 실체 변수는 클래스의 객체가 생성되기 전에는 존재하지 않기 때문. 그러나, 정적 메쏘드는 정적 변수나 지역 변수(local variable)는 참조할 수 있다.

23 정적 클래스 멤버(Static Class Member)
다음 예제 프로그램은 정적 변수를 사용하여 Slogan 객체가 몇 개가 생성되었는지를 추적하고 정적 메쏘드를 사용하여 그 정보를 확인할 수 있게 한다. SloganCounter.java (국: 299쪽,영:294쪽) 참조 Slogan.java (국:301쪽,영: 295쪽) 참조

24 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.");

25 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

26 Slogan.java public class Slogan { private String phrase;
private static int count = 0; public Slogan (String str) { phrase = str; count++; } public String toString() { return phrase; } public static int getCount () { return count; } }

27 목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces)
열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout)

28 클래스 관계(Class Relationships)
소프트웨어 시스템의 클래스들은 서로 다양한 종류의 관계를 가질 수 있다: 의존성(Dependency): A uses B 집합체(Aggregation): A has-a B 상속(Inheritance): A is-a B 이 장에서는 의존성과 집합체만을 다루고 상속은 8장에서 다루도록 한다.

29 의존성(Dependency) 한 클래스가 다른 클래스에 의존한다는 것을 의미
다른 클래스의 메쏘드를 호출할 때 “uses” 관계가 됨 앞의 많은 예들에서 한 클래스가 다른 클래스에 의존하는 상황을 보았다. 보통 다른 클래스에 의존 않는 복잡한 구조의 클래스는 바람직하지 않다. 하지만 클래스들 사이의 의존성은 최소화되어야 한다. 좋은 설계를 위해서는 클래스들의 의존성이 균형 있게 설계되어야 한다.

30 의존성(Dependency) 다음 예제는 유리수를 나타내는 RationalNumber 클래스를 정의하고 있다.
유리수는 두 정수의 비로 표현할 수 있는 값이다. RationalTester 클래스는 RationalNumber 클래스에 의존하고 있다. RationalTester.java (국: 303쪽, 영: 297쪽) 참조 RationalNumber.java (국: 305쪽, 영: 299쪽) 참조

31 RationalTester.java //******************************************************************* //  RationalTester.java      저자: 루이스와 롭터스 //  여러 Rational 객체의 사용을 시험하는 드라이버. public class RationalTester {    //    //  몇 개의 유리수 객체들을 만들어 다양한 연산을 수행한다.    public static void main (String[] args)    {       RationalNumber r1 = new RationalNumber (6, 8);       RationalNumber r2 = new RationalNumber (1, 3);       RationalNumber r3, r4, r5, r6, r7;

32 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);

33 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

34 RationalNumber.java //******************************************************************* //  RationalNumber.java       저자: 루이스와 롭터스 //  분자와 분모를 가진 유리수를 표현한다. public class RationalNumber {    private int numerator, denominator;    //    //  구성자: 0이 아닌 분모를 갖고 부호가 있는 분자를 갖도록 // 유리수를 설정한다.    public RationalNumber (int numer, int denom)    {       if (denom == 0)          denom = 1;

35 RationalNumber.java (cont’d)
      // 부호를 갖는 분자를 만든다.       if (denom < 0)       {          numer = numer * -1;          denom = denom * -1;       } numerator = numer;       denominator = denom;       reduce();    }  //    //  이 유리수의 분모를 반환한다.     //    public int getNumerator ()    {       return numerator;

36 RationalNumber.java (cont’d)
    //    //  이 유리수의 분자를 반환한다.     //    public int getDenominator ()    {       return denominator;    }   //    //  이 유리수의 역수를 반환한다.    public RationalNumber reciprocal ()       return new RationalNumber (denominator, numerator);

37 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);    }

38 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);    }   

39 RationalNumber.java (cont’d)
 //    // 이 유리수를 매개변수로 받은 유리수와 곱한다.    //    public RationalNumber multiply (RationalNumber op2)    {       int numer = numerator * op2.getNumerator();       int denom = denominator * op2.getDenominator();       return new RationalNumber (numer, denom);    }

40 RationalNumber.java (cont’d)
   //    // 이 유리수를 매개변수로 받은 유리수로 나눈다.    // 두 번째 피연산자의 역수를 곱함으로써 나눗셈을 한다.    public RationallNumber divide (RationalNumber op2)    {       return multiply (op2.reciprocal());    }       //  유리수가 전달된 매개변수와 같은지 결정한다. // 둘 다 약분되었다고 가정한다.    public boolean equals (RationalNumber op2)       return ( numerator == op2.getNumerator() &&                denominator == op2.getDenominator() );

41 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;    }

42 RationalNumber.java (cont’d)
   //    //  최대공약수로 분모와 분자를 나눔으로써 유리수를 약분한다.    private void reduce ()    {       if (numerator != 0)       {          int common = gcd (Math.abs(numerator), denominator);     numerator = numerator / common;          denominator = denominator / common;       }    }

43 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;    } }

44 집합체(Aggregation) 집합체 객체(aggregate object)는 다른 객체들로 만들어진 객체를 말한다.
따라서 집합체(aggregation)는 ‘has-a’ 관계를 갖는다. A car has an engine 소프트웨어 세계에서 집합체 객체(aggregate object)는 실체 데이터로 다른 객체들에 대한 참조를 포함한다. 집합체 객체는 그것을 이루는 객체들에 의해 요소 별로 정의된다. 집합체는 보통 그것을 이루는 객체들에 의존하는 특별한 관계이다

45 집합체(Aggregation) 다음 예에서 Student 객체는 부분적으로 두 개의 Address 객체들로 구성되어 있다.
StudentBody.java (국: 309쪽, 영: 304쪽) 참조 Student.java (국: 310쪽, 영: 306쪽) 참조 Address.java (국: 311쪽, 영: 307쪽) 참조 UML에서 집합체는  두 클래스 사이에 선으로 표현되는 데 집합체 클래스 부근에 끝이 다이아몬드인 선으로 표현된다.

46 UML에서의 집합체 uses has-a 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 has-a

47 StudentBody.java public class StudentBody {
   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);      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 …..

48 Student.java // 대학생을 표현한다. public class Student {
//  대학생을 표현한다. 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;    }

49 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;    } }

50 Address.java // 거리 주소를 표현한다. public class Address {
//  거리 주소를 표현한다. 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;    }

51 Address.java  (Cont’d)    //    //  이 Address 객체의 스트링 표현을 반환한다.    public String toString()    {       String result;       result = streetAddress + "\n";       result += city + ", " + state + "  " + zipCode;       return result;    } }

52 this 참조 this 참조는 객체에게 자신을 참조할 수 있도록 해준다.
다음과 같이 호출되는 tryMe 메쏘드에서 this 참조가 사용된다면: obj1.tryMe(); obj2.tryMe(); 첫 번째 호출에서는 this 참조가 obj1을 참조하고 두 번째에서는 this 참조가 obj2를 참조하게 된다.

53 this 참조 흔히 this 참조는 구성자에서 실체 변수를 같은 이름을 갖는 매개변수로부터 구분하는데 사용된다. 예를 들어 4장의 Account 클래스의 구성자는 다음과 같이 다시 작성할 수 있다: public Account (Sring owner, long account, double initial){ name = owner; acctNumber = account; balance = initial; } public Account (Sring name, long acctNumber, double balance){ this.name = name; this.acctNumber = acctNumber; this.balance = balance; }

54 목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces)
열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout)

55 인터페이스(Interfaces) Java 인터페이스는 상수들과 추상 메쏘드들의 집합이다.
추상 메쏘드(abstract method)는 바디의 구현 없는 메쏘드 헤더(header) 이다. 추상 메쏘드는 abstract 조정자를 사용하여 정의할 수 있는데 인터페이스 안의 모든 메쏘드는 추상 메쏘드이기 때문에 보통 abstract 조정자를 생략한다. 인터페이스는 이를 구현하는 클래스가 구현할 메쏘드의 집합으로 설정된다.

56 interface는 예약어(reserved word) 이다.
인터페이스(Interfaces) interface는 예약어(reserved word) 이다. 인터페이스의 어떤 메쏘드도 정의되지 않는다. (body를 갖지 않는다) public interface Doable { void doThis(); int doThat(); void doThis2 (float value, char ch); boolean doTheOther (int num); } 각 메쏘드 헤더 뒤에는 세미콜론(;)이 온다.

57 인터페이스(Interfaces) 인터페이스는 실체화(instantiate)될 수 없다.
인터페이스 안의 메쏘드들은 기본적으로 공용 가시성을 가지며, 보통 public 조정자를 생략한다. (교재의 예제에서는 생략되어 있지 않음) 클래스는 인터페이스를 다음과 같은 형식으로 구현한다: 클래스 헤더에 인터페이스 구현을 선언하고 인터페이스의 모든 메쏘드들에 대한 정의를 제공해야 한다. (정의가 누락된 메쏘드가 있으면 컴파일러 오류 발생)

58 인터페이스(Interfaces) public class CanDo implements Doable {
public void doThis () // whatever } public void doThat () // etc. implements: 예약어 Doable에 있는 모든 메쏘드 들을 정의해야 한다.

59 인터페이스(Interfaces) 인터페이스를 구현하는 클래스는 인터페이스의 메쏘드 외에 다른 일반 메쏘드도 구현할 수 있다.
인터페이스를 구현하는 클래스는 인터페이스의 메쏘드 외에 다른 일반 메쏘드도 구현할 수 있다. Complexity.java (국: 314쪽, 영: 310쪽) 참조 Question.java (국: 315쪽, 영: 311쪽) 참조 MiniQuiz.java (국: 317쪽, 영: 313쪽) 참조 인터페이스는 추상 메쏘드(abstract method) 외에 상수(constant)를 포함할 수 있다. 만약 어떤 클래스가 인터페이스를 구현했다면 그 안의 모든 상수에 대한 접근권한을 얻는다.

60 Complexity.java  //******************************************************************* //  Complexity.java       저자: 루이스와 롭터스 //  명시적인 복잡도를 할당할 수 있는 객체에 대한 인터페이스를 // 표현한다.  public interface Complexity {    void setComplexity (int complexity);    int getComplexity(); }

61 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;    }

62 Question.java (cont’d)
  //    //  이 질문에 대한 복잡도 수준을 설정한다.    //    public void setComplexity (int level)    {       complexityLevel = level;    }    //  이 질문에 대한 복잡도 수준을 반환한다.    public int getComplexity()       return complexityLevel;

63 Question.java (cont’d)
  //    //  질문을 반환한다.    //    public String getQuestion()    {       return question;    }    //  이 질문에 대한 답을 반환한다.    public String getAnswer()       return answer;

64 Question.java (cont’d)
 //    //  후보 답이 정답과 같으면 참을 반환한다.    //    public boolean answerCorrect (String candidateAnswer)    {       return answer.equals(candidateAnswer);    }    //  질문과 답을 스트링으로 반환한다.    public String toString()       return question + "\n" + answer; }

65 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);

66 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() + ")");

67 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

68 인터페이스(Interfaces) 하나의 클래스는 여러 개의 인터페이스를 구현할 수 있다.
하나의 클래스는 여러 개의 인터페이스를 구현할 수 있다. 이 경우에 클래스는 나열된 모든 인터페이스들의 모든 메쏘드들을 구현해야 한다. 클래스가 구현하는 모든 인터페이스들은 implements 절에 콤마로 구분해서 나열해야 한다. class ManyThings implements interface1, interface2 { // all methods of both interfaces }

69 Comparable 인터페이스 Java 표준 클래스 라이브러리는 많은 유용한 인터페이스들을 갖고 있다.
Comparable 인터페이스는 두 개의 객체를 비교하는 compareTo()라고 하는 하나의 추상 메쏘드를 갖고 있다. 5장에서 String 클래스의 compareTo() 메쏘드를 다룬 바 있다. String 클래스는 두 개의 문자열을 사전적 순서로 정렬하는데 사용할 수 있는 Comparable 인터페이스를 구현한다.

70 Comparable 인터페이스 하나의 객체와 다른 객체를 비교하는 일반적인 메커니즘을 제공하기 위해 어느 클래스나 Comparable 인터페이스를 구현할 수 있다. if (obj1.compareTo(obj2) < 0) System.out.println ("obj1 is less than obj2"); 위의 예제에서 알 수 있듯이 compareTo() 메쏘드는 obj1이 obj2보다 작으면 음의 정수, 같으면 0, 크면 양의 정수를 반환한다. Comparable 인터페이스를 구현하는 클래스를 구현할 때 위와 같은 (음수, 0, 양수) 결과가 나오도록 구현해야 한다.

71 Comparable 인터페이스 클래스의 한 객체가 다른 객체보다 작다는 것의 의미를 결정하는 것은 각 클래스의 설계자에게 달려있다. 예를 들면, Employee 클래스의 compareTo() 메쏘드를 정의하고자 한다면 직원(employee) 객체 들의 대소 관계를 이름의 알파벳 순으로 할지 아니면 직원번호 순으로 할지 결정해야 한다. 이러한 메쏘드의 구현은 상황에 따라 아주 간단할 수도 있고 아주 복잡할 수도 있다.

72 Iterator 인터페이스 5장에서 소개했던 반복자(iterator)는 객체들의 묶음을 한 번에 한 개씩 처리하도록 하는 메쏘드를 갖는 객체이다. iterator는 아래와 같은 세 개의 메쏘드를 갖고 있는 Iterator 인터페이스를 구현하여 정의된다. hasNext() 메쏘드: 부울 값 반환 (아직 처리할 원소가 남아있으면 참(true), 없으면 거짓(false)) next() 메쏘드: 다음 객체 반환 remove() 메쏘드: 가장 최근 next()에 의해 반환된 항목 제거

73 Iterator 인터페이스 Iterator 인터페이스를 구현함으로써 클래스는 그 타입의 객체들의 반복자를 생성할 수 있다.
반복자가 생성이 되면 for-each 버전의 for 루프를 사용하여 반복자 안의 항목들을 하나씩 순서대로 처리할 수 있다.

74 Iterator 인터페이스 BookList가 Book 객체들에 대한 반복자일 경우
for (Book myBook : BookList) System.out.println (myBook); is equivalent to Book myBook; while (BookList.hasNext()) { myBook = BookList.next(); System.out.println (myBook); }

75 인터페이스(Interfaces) 인터페이스를 구현하지 않고 그 안의 메쏘드만 구현하는 클래스를 작성할 수 있다.
인터페이스를 구현하지 않고 그 안의 메쏘드만 구현하는 클래스를 작성할 수 있다. 예: Comparable 인터페이스를 구현하지 않고 compareTo() 메쏘드만 구현 그러나, 클래스와 인터페이스의 관계를 갖게 하는 것이 Java로 하여금 위에서 소개한 방식으로 객체를 다루게 해 준다. 인터페이스는 Java의 객체지향 설계의 하나의 중요한 요소이다. 9장에서 인터페이스에 대해 자세히 다룬다

76 목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces)
열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout)

77 열거 타입(Enumerated Types)
3장에서 새로운 데이터 타입을 정의하고 그 타입의 모든 값들을 열거하는 열거 타입의 개념을 소개하였다. enum Season {winter, spring, summer, fall} 열거타입이 한번 생성되면 그 새로운 타입은 다음과 같이 변수를 정의하는데 사용될 수 있다. Season time; 위에서 변수 time에 할당할 수 있는 값은 enum Season 정의에 열거된 값으로 한정된다.

78 열거 타입(Enumerated Types)
열거 타입은 특별한 종류의 클래스이다. 열거 타입의 값들은 그 타입의 객체이다. 예: fall은 Season 타입의 객체이다. 따라서 다음과 같은 배정문이 유효하다. time = Season.fall;

79 열거 타입(Enumerated Types)
열거 타입 정의는 단순한 값들의 열거 이상의 의미를 갖는다. 열거 타입은 클래스와 같아서, 추가적인 실체 데이터나 메쏘드를 더 포함시킬 수 있다. 또한 enum 구성자(constructor)를 정의할 수도 있다. 이 경우, 열거 타입을 위해 열거되는 각각의 값이 구성자를 호출한다. Season.java (국: 321쪽, 영: 318쪽) SeasonTester.java (국: 322쪽, 영: 319쪽) 참고: 이 열거 타입은 Java 1.5 이상에서 지원되는 새로운 기능이다.

80 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; } }

81 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

82 열거 타입(Enumerated Types)
각 열거 타입은 그 타입의 모든 가능한 값들을 반환하는 values()라는 정적 메쏘드를 포함한다 이 리스트는 반복자로 각 값을 처리하기 위해 for 루프의 새로운 버전을 사용할 수 있다. 열거 타입은 자신의 정의를 벗어나서 실체화 될 수 없다. 잘 정의된 열거 타입은 데이터 관리에 있어 다양하면서도 type-safe한 구조를 제공한다.

83 목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces)
열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout)

84 메쏘드 설계 high-level 설계의 쟁점 사항: low-level 설계의 쟁점 사항
주요 클래스와 객체의 식별 주요 임무의 부여 low-level 설계의 쟁점 사항 주요 메쏘드의 설계 단순한 메쏘드들은 설계하는데 크게 신경 쓸 필요가 없겠으나 어떤 메쏘드들은 효과적이고 세련된 시스템 설계가 될 수 있도록 세심한 계획이 요구되기도 한다.

85 메쏘드 설계 알고리즘(algorithm)은 어떤 문제를 해결하는 단계별 과정이다
예: 조리법이나 여행 길 안내 등도 하나의 알고리즘이다 각 메쏘드는 목적에 도달하는 방법을 결정하는 알고리즘을 구현한다 알고리즘은 흔히 코드 문장과 영어 절을 혼합한 의사코드(pseudocode)로 기술된다

86 메쏘드 분해 하나의 메쏘드를 전체적으로 파악할 수 있도록 작게 만들어야 한다
하나의 메쏘드를 전체적으로 파악할 수 있도록 작게 만들어야 한다 너무 큰 메쏘드는 이해를 돕기 위해 여러 개의 작은 메쏘드로 분해할 필요가 있다 주어진 목적을 달성하기 위해 public 메쏘드는 하나 이상의 private 메쏘드들을 호출하기도 한다 보조 역할을 하는 메쏘드들도 필요하다면 다른 보조 역할을 하는 메쏘드들을 호출할 수 있다.

87 메쏘드 분해 메쏘드 분해가 필요한 예를 살펴보자 피그라틴어는 가상의 언어로 단어들을 다음과 같이 변경한다. book
영어를 피그라틴(Pig Latin)어로 번역하는 프로그램 피그라틴어는 가상의 언어로 단어들을 다음과 같이 변경한다. 자음으로 시작되는 단어의 경우 그 자음을 끝으로 이동하고 “ay” 를 첨부한다 모음으로 시작된 단어들은 “yay” 를 끝에 첨부한다 단어 시작의 “ch”, “st”, “sh”, “cr”, “th”, … 등의 자음군은 함께 끝으로 이동하고 “ay” 첨부한다 예: book ookbay table abletay item itemyay chair airchay

88 메쏘드 분해 문장을 피그라틴어로 번역하는 프로그램을 하나의 메쏘드로 작성한다면 너무 복잡할 것이다.
문장을 피그라틴어로 번역하는 프로그램을 하나의 메쏘드로 작성한다면 너무 복잡할 것이다. 그래서 번역 메쏘드를 자연스럽게 여러 개의 작은 조각으로 분해하는 설계가 바람직하다. 문장을 번역하는 일은 3개의 경우로 분리된 각 단어를 번역하는 처리로 분해시킬 수 있다 단어 번역의 3가지 처리 경우: 모음으로 시작하는 경우 혼성자음 sh, cr, th 등으로 시작하는 경우 하나의 자음으로 시작하는 경우

89 메쏘드 분해 PigLatin.java (국: 324쪽, 영: 320쪽) 참조
PigLatinTranslator.java (국: 325쪽, 영: 323쪽) 참조 UML 클래스 다이어그램에서 변수(variable)나 메쏘드(method)의 가시성(visibility)은 특수 문자를 사용하여 표현할 수 있다. Public 멤버는 플러스 기호로 표시 Private 멤버는 마이너스 기호로 표시

90 PigLatin 프로그램을 위한 UML 다이어그램
+ main (args : String[]) : void + translate (sentence : String) : String - translateWord (word : String) : String - beginsWithVowel (word : String) : boolean - beginsWithBlend (word : String) : boolean PigLatinTranslator

91 PigLatin.java //******************************************************************* //  PigLatin.java       Author: Lewis/Loftus //  메쏘드 분해 개념을 보인다. import java.util.Scanner; public class PigLatin { // // Reads sentences and translates them into Pig Latin. public static void main (String[] args) String sentence, result, another; Scanner scan = new Scanner (System.in);

92 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"));

93 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

94 PigLatinTranslator.java //******************************************************************* //  PigLatinTranslator.java       저자: 루이스와 롭터스// //  영어를 피그라틴어로 번역하는 시스템을 표현한다. //  메쏘드 분리와 StringTokenizer의 사용을 보여 준다 import java.util.Scanner; public class PigLatinTranslator {    //    //  단어들로 이루어진 한 문장을 피그라틴어로 번역한다.    //    public static String translate (String sentence)    {       String result = "";

95 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 static String translateWord (String word)    {       String result = "";

96 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 static boolean beginsWithVowel (String word)    {       String vowels = "aeiouAEIOU";       char letter = word.charAt(0);       return (vowels.indexOf(letter) != -1);

97 PigLatinTranslator.java (Cont’d)
    //  명시된 단어가 특정 두 문자의 접두사로 시작하는지 결정한다. //    private static 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") );    } }

98 매개변수로서의 객체 메쏘드 설계와 관련한 또 하나의 중요한 주제가 매개변수를 메쏘드로 전달하는 방법이다
메쏘드 설계와 관련한 또 하나의 중요한 주제가 매개변수를 메쏘드로 전달하는 방법이다 Java 메쏘드에서는 모든 매개변수가 값으로 전달된다( passed by value) (4장 참조) 실 매개변수(actual parameter: 호출문에 있는)의 값이 복사되어 형식 매개변수(formal parameter: 메쏘드 헤더에 있는)에 저장된다 그러므로 매개변수 전달 (parameter passing) 은 배정문(assignment statement)과 비슷하다. 객체가 메쏘드에 전달될 때는 실 매개변수와 형식 매개변수 서로가 서로의 별명(alias)이 된다 (3.1장 참조)

99 메쏘드로의 객체 매개변수 전달 메쏘드가 매개변수를 받아 수행한 작업이 메쏘드 밖에 영향을 미칠 수도 있고 미치지 않을 수도 있다 참조를 사용할 경우 메쏘드 밖에도 영향을 줌 ParameterTester.java (국: 329쪽, 영: 327쪽) 참조 ParameterModifier.java (국: 330쪽, 영: 329쪽) 참조 Num.java (국: 331쪽, 영: 330쪽) 참조 객체의 내부 상태(state)를 변화시킬 때와 참조되는 객체를 변화시킬 때의 차이를 유의하여 보자

100 ParameterTester.java //******************************************************************* //  다양한 타입의 매개변수 전달 효과를 보인다. class ParameterTester {    //    //  changeValues 메쏘드에 실 매개변수로 사용될 변수들(하나는 기본타입,    //  두 개는 객체들)을 설정한다. 메쏘드 호출 전과 호출 후 값을 인쇄한다.    //    public static void main (String[] args)    {       ParameterModifier modifier = new ParameterModifier();       int a1 = 111;       Num a2 = new Num (222);       Num a3 = new Num (333);

101 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: a a a3 Before changing the values: f f f3 After changing the values: f f f3 After calling changeValues:

102 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:");    } }

103 Num.java // 하나의 정수를 객체로 표현한다. class Num { private int value;
//  하나의 정수를 객체로 표현한다. class Num {    private int value;    //  초기값을 저장하여 Num 객체를 설정한다.    public Num (int update)    {      value = update; }    //  새로 명시된 값으로 저장된 값을 설정한다.    public void setValue (int update)    //  저장된 정수 값을 문자열로 반환한다.    public String toString ()    {      return value + ""; } }

104 메쏘드 중복정의(Overloading)
메쏘드 중복정의는 동일한 메쏘드 이름으로 여러 개의 메쏘드를 정의하는 것이다 만약 메쏘드가 중복정의 되었다면 메쏘드 이름만으로는 어느 메쏘드를 호출할 지 결정할 수 없다 중복정의되는 각 메쏘드의 시그너처(signature)는 반드시 유일해야 한다 메쏘드의 시그너처(signature)는 메쏘드 이름, 매개변수의 수, 각 매개변수의 타입 및 순서를 포함한다

105 메쏘드 중복정의(Overloading)
컴파일러는 매개변수를 분석하여 어느 메쏘드가 호출되어야 할지 결정한다. float tryMe(int x) { return x ; } result = tryMe(25, 4.32) 호출(Invocation) float tryMe(int x, float y) { return x*y; }

106 메쏘드 중복정의(Overloading)
println 메쏘드의 중복정의: println (String s) println (int i) println (double d) ... 다음 명령문들은 각기 다른 버전의 println 메쏘드를 호출 한다: System.out.println ("The total is:"); System.out.println (total);

107 메쏘드 중복정의(Overloading)
메쏘드의 반환 타입(return type)은 메쏘드의 시그너처에 포함되지 않는다 즉, 중복정의 된 메쏘드는 반환 타입만 달라서는 안된다. 메쏘드 호출에는 반환타입이 직접적으로 명시되지 않는다 구성자(Constructor)도 중복될 수 있다 구성자를 중복정의 함으로써 객체를 초기화하고 생성하는 다양한 방법을 제공한다

108 목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces)
열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout)

109 테스트(Testing) 테스트(Testing)라는 용어는 소프트웨어 개발에서 여러 가지 방식으로 적용될 수 있다
물론 테스트에는 완성된 프로그램을 다양한 입력으로 실행시키는 것이 포함된다 또한 개발 중인 시스템의 품질을 판단하기 위해서 사람이나 컴퓨터에 의해 수행되는 다양한 평가들을 포함한다. 어떤 평가는 코드 작성이 시작되기도 전에 이루어져야 한다 문제를 일찍 찾아낼수록 그것을 고치기 쉽고 비용도 적게 든다

110 테스트(Testing) 테스트의 목적은 오류(error)를 찾아내는 것이다
오류를 찾아 고침으로써 프로그램의 품질을 높여나가게 된다 모든 오류가 제거되었다고 확신하는 것은 불가능하다 그럼 언제까지 테스트를 해야 할 것인가? 비현실적인 답: 영원히 계속 궁색한 답: 시간이 되는 동안 보다 나은 답: 발견하지 못한 오류에 대한 위험을 스스로 부담할 의사가 생길 때까지

111 검토(Reviews) 검토는 여러 사람들이 모여 설계 문서나 코드 부분을 세심하게 점검하는 것이다.
검토는 여러 사람들이 모여 설계 문서나 코드 부분을 세심하게 점검하는 것이다. 이것은 인적 수준의 테스트이며, 일반적으로 사용되고 있고 나름의 효과도 있다. 설계나 코드를 다른 사람에게 제공하는 것은: 스스로 보다 신중하게 생각하도록 만들고 다른 사람들의 관점을 들어볼 수 있도록 한다. 검토는 종종 검사(inspection) 혹은 워크쓰루(walkthrough)로 불리기도 한다.

112 테스트 케이스(Test Cases) 테스트 케이스는 입력, 사용자 동작, 혹은 다른 초기 조건과 예상된 출력들의 집합이다
테스트 케이스는 입력, 사용자 동작, 혹은 다른 초기 조건과 예상된 출력들의 집합이다 보통 저장하여 재사용할 수 있도록 테스트 케이스들을 형식에 맞추어 편성하여 완전한 테스트 모음(test suite)을 만든다 중대형의 시스템에서 테스트 프로세스는 세심한 관리를 요한다 많은 조직에서 테스트를 전담하기 위한 독립적인 품질 보장 (Quality Assurance (QA)) 부서를 따로 두고 있다

113 결함 테스트와 회귀 테스트 결함 테스트(Defect testing)는 테스트 케이스들의 실행을 통해 오류를 찾아내는 작업이다.
오류를 수정하는 행위가 새로운 오류를 발생시킬 수 있다. 오류들의 수정 후에는 회귀 테스트(regression testing)를 수행해야 한다. 회귀 테스트: 이전 수행했던 테스트 케이스들을 다시 적용해봐서 새로운 오류가 생겨나지 않았음을 확인하는 작업 모든 가능한 입력과 사용자 동작에 대한 테스트 케이스를 만들어 내는 것은 불가능하다. 그러므로 문제를 최대한 찾아낼 수 있도록 테스트들을 설계해야 한다.

114 Black-Box 테스트 black-box 테스트는 내부 로직(logic)의 고려 없이 테스트 케이스를 개발한다
이 경우 테스트는 입력과 그에 기대되는 출력에 기반을 둔다

115 White-Box 테스트 White-box 테스트는 코드의 내부 구조와 구현의 검사에 중점을 두고 있다
이 테스트의 목적은 프로그램의 모든 부분이 적어도 한 번은 테스트됨을 확인하는 것이다 코드의 실행 경로는 프로그램에 있는 조건문과 반복문의 지배를 받게 된다 좋은 테스트는 black-box와 white-box 테스트 모두를 포함하는 것이다

116 목차 소프트웨어 개발 과정 클래스와 객체의 식별 Static 변수와 메쏘드 클래스 관계 인터페이스(Interfaces)
열거 타입(Enumerated Types) 메쏘드 설계 테스트 GUI 설계 및 레이아웃(Layout)

117 GUI 설계 소프트웨어의 목적이 사용자의 문제 해결을 돕는 것이라는 것을 항상 기억해야 한다
소프트웨어의 목적이 사용자의 문제 해결을 돕는 것이라는 것을 항상 기억해야 한다 그 목적을 위하여, GUI 설계자는: 사용자를 파악하고 사용자의 실수를 예방하고 사용자의 능력을 최대로 활용하고 일관성을 가져야 한다. 각각에 대해 좀더 자세히 보도록 하자

118 사용자 파악 사용자 파악을 위해 다음을 이해해야 한다: 사용자에 따라 위의 사항이 달라질 수 있다는 것을 인식해야 한다
사용자가 진정 요구하는 것 사용자의 일반적 업무 컴퓨터 처리와 문제에 관련된 전문지식 정도 사용자에 따라 위의 사항이 달라질 수 있다는 것을 인식해야 한다 사용자에게는 인터페이스가 바로 프로그램이라는 것을 유의해야 한다

119 사용자 실수 방지 가능한 한 사용자 인터페이스는 사용자의 실수가 최소화 되도록 설계되어야 한다
가능한 한 사용자 인터페이스는 사용자의 실수가 최소화 되도록 설계되어야 한다 특정한 일을 달성하는 여러 GUI 컴포넌트 중에서 부적절한 동작을 방지하고 유효하지 않은 입력을 피하는 가장 좋은 컴포넌트를 선택하도록 노력해야 한다 예: 유효한 경우가 단지 몇 개만 존재할 경우, text field 보다는 메뉴나 라디오 버튼들을 통해 입력 받는 것이 더 낫다 오류 메시지는 사용자로 하여금 적절하게 유효한 입력을 할 수 있도록 안내해야 한다

120 사용자 능력의 최대 활용 모든 사용자가 다 같지는 않다. 정통한 사용자를 종종 파워유저(power user)라 한다
어떤 사용자가 다른 사용자에 비해 더 시스템에 익숙할 수 있다. 정통한 사용자를 종종 파워유저(power user)라 한다 적절하다면 하나의 일을 완수하는데 여러 가지 방법을 제공하여야 한다 "wizards"를 제공하여 처리과정을 사용자가 자동으로 순차적으로 진행할 수 있게 하거나 파워유저를 위해서는 단축키(short cut)를 제공 방해가 되지 않는 범위에서 도움말 제공

121 일관성 유지 일관성은 중요하다 – 사용자는 어떤 것의 모양이나 일하는 방식 등에 쉽게 익숙해지게 된다
일관성은 중요하다 – 사용자는 어떤 것의 모양이나 일하는 방식 등에 쉽게 익숙해지게 된다 색상도 유사한 정보나 처리를 나타내기 위해 일관성을 가져야 한다 화면 배치도 시스템의 각 부분에 있어서 일관성을 유지해야 한다. 예를 들면, 오류 메시지도 항상 같은 위치에 나타나도록 해야 한다

122 레이아웃 관리자(Layout Manager)
Java 표준 클래스 라이브러리가 제공하는 사전 정의된 레이아웃 관리자: Flow Layout Border Layout Card Layout Grid Layout GridBag Layout AWT에 정의 Box Layout Overlay Layout Swing에 정의

123 레이아웃 관리자(Layout Manager)
각 컨테이너는 초기 설정된 레이아웃 관리자를 갖고 있다. 그러나 명시적으로 다른 것으로 대치할 수 있다. 각 레이아웃 관리자는 컴포넌트들의 배치를 조정하는 자신만의 특별한 규칙을 가지고 있다 어떤 레이아웃 관리자들은 컴포넌트의 선호 크기나 정렬 방식을 고려하는 반면에 다른 레이아웃 관리자들은 이들을 고려하지 않는다. 레이아웃 관리자는 컴포넌트가 컨테이너에 추가되거나 컨테이너의 크기가 바뀔 때 레이아웃 재 조정을 시도한다

124 레이아웃 관리자(Layout Manager)
컨테이너의 setLayout() 메쏘드를 사용하여 컨테이너의 레이아웃 관리자를 바꿀 수 있다 JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); 다음 예제 프로그램에서는 tab 달린 페인(tabbed pane)의 사용을 소개하는데, 그것은 사용자가 여러 페인들 중 현재 보이는 것을 선택할 수 있게 하는 컨테이너이다. LayoutDemo.java (국: 341쪽, 영: 340쪽) 참조 IntroPanel.java (국: 342쪽, 영: 341쪽) 참조

125 LayoutDemo.java //******************************************************************** // LayoutDemo.java 저자: Lewis/Loftus // 흐름, 영역, 격자, 그리고 상자 레이아웃의 사용을 보여준다. import javax.swing.*; public class LayoutDemo { // // tabbed pane을 포함하고 있는 프레임을 준비한다. // 각각의 tabbed pane은 상이한 레이아웃 관리자를 보여준다. public static void main (String[] args) JFrame frame = new JFrame ("Layout Manager Demo"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);

126 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); }

127 디폴트 레이아웃인 FlowLayout 사용
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); } 디폴트 레이아웃인 FlowLayout 사용

128 흐름 레이아웃(Flow Layout) 흐름 레이아웃(Flow layout)은 컴포넌트들을 한 행(row)에 가능한 한 많이 놓고 그 행이 다하면 다음 행에 놓는다 컨테이너에 더해진 모든 컴포넌트들을 놓기에 필요한 만큼 행이 추가 된다. 컴포넌트들은 컨테이너에 더해진 순서대로 디스플레이 된다 컴포넌트는 윈도우 내에서 가운데정렬로 초기화 되어있다. 그러나 좌측정렬이나 우측정렬도 가능하다 컴포넌트들 사이의 수평간격(horizontal gap)과 수직 간격(vertical gap) 도 명시적으로 설정할 수 있다. FlowPanel.java (국: 344쪽, 영: 343쪽) 참조

129 FlowPanel.java //******************************************************************** // FlowPanel.java 저자: Lewis/Loftus / // LayoutDemo 프로그램에서 흐름 레이아웃 // 관리자를 보여주는 패널을 나타낸다 //******************************************************************** import java.awt.*; import javax.swing.*; public class FlowPanel extends JPanel { // // 흐름 레이아웃이 위치에 어떻게 영향을 미치는지 보이도록, // 몇 개의 버튼들을 가진 패널을 준비한다. public FlowPanel () setLayout (new FlowLayout()); setBackground (Color.green);

130 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); }

131 영역 레이아웃(Border Layout)
North South Center East West

132 영역 레이아웃(Border Layout)
각 영역은 하나의 컴포넌트를 가질 수 있다. (참고: JPanel과 같은 컨테이너도 하나의 컴포넌트이다) 바깥쪽 4개의 각 영역은 포함하고 있는 컴포넌트를 수용하기 위해 필요한 만큼 커진다 만일 동, 서, 남, 북의 영역에 어떤 컴포넌트도 부착되지 않는다면 그 영역들은 전체적인 레이아웃에서 조금의 공간도 차지하지 않는다. 중앙 영역은 가용 공간 전부를 채울 수 있도록 필요한 만큼 확장된다. BorderPanel.java (국: 347쪽, 영: 346쪽) 참조

133 BorderPanel.java //******************************************************************** // BorderPanel.java 저자: Lewis/Loftus // // LayoutDemo 프로그램에서 영역 레이아웃 관리자를 보여주는 // 패널을 나타낸다. import java.awt.*; import javax.swing.*; public class BorderPanel extends JPanel { // // 영역 레이아웃이 위치, 모양, 그리고 크기에 어떻게 영향을 미치는지 보이도록, // 영역 레이아웃의 각 영역에 하나의 버튼을 가진 패널을 준비한다. public BorderPanel()

134 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); }

135 격자 레이아웃(Grid Layout) 격자 레이아웃(grid layout)은 행과 열의 직사각형 격자에 컨테이너의 컴포넌트들을 배치한다 하나의 컴포넌트는 격자상의 하나의 칸(cell)에 놓여지며, 모든 칸들은 동일한 크기를 갖는다. 컴포넌트가 추가될 때마다 왼쪽에서 오른쪽으로 또 위에서 아래로 격자를 채워나가도록 초기화 되어 있다 각 격자 칸의 크기는 컨테이너의 전체 크기에 의해 결정되어진다 GridPanel.java (국: 349쪽, 영: 349쪽) 참조

136 GridPanel.java //******************************************************************** // GridPanel.java 저자: Lewis/Loftus // LayoutDemo 프로그램에서 격자 레이아웃 관리자를 // 보여주는 패널을 나타낸다. import java.awt.*; import javax.swing.*; public class GridPanel extends JPanel { // // 격자 레이아웃이 위치, 모양, 크기에 어떻게 영향을 미치는지 보이도록, // 몇 개의 버튼들을 가진 패널을 준비한다. public GridPanel()

137 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); }

138 상자 레이아웃(Box Layout) 상자 레이아웃(box layout)은 컴포넌트들을 하나의 행 또는 하나의 열에 수평 또는 수직으로 조직한다. 컴포넌트들은 컨테이너에 추가될 때 마다 위에서 아래로 혹은 왼쪽에서 오른쪽으로 배치된다 상자 레이아웃을 사용하는 여러 개의 컨테이너를 결합하여 여러 가지 다른 배치를 만들어낼 수 있다

139 상자 레이아웃(Box Layout) 투명 컴포넌트(Invisible components)는 컴포넌트들 사이에 공간을 만들기 위해 상자 레이아웃 컨테이너에 추가될 수 있다. 두 종류의 투명 컴포넌트가 있다. 고정 영역(Rigid areas): 고정된 크기를 가짐 탄력 영역(Glue): 남는 공간을 사용 고정 영역은 Box 클래스의 createRigidArea() 메쏘드를 사용하여 생성된다. 탄력 영역은 createHorizontalGlue() 메쏘드나 createVerticalGlue() 메쏘드를 사용하여 생성한다. See BoxPanel.java (국: 352쪽, 영: 352 쪽) 참조

140 BoxPanel.java public class BoxPanel extends Jpanel {
public BoxPanel() { setLayout (new BoxLayout (this, BoxLayout.Y_AXIS)); 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 (Box.createRigidArea (new Dimension (0, 10))); add (b2); add (Box.createVerticalGlue()); add (b3); add (b4); add (Box.createRigidArea (new Dimension (0, 20))); add (b5); }

141 테두리(Borders) 테두리(border)는 컴포넌트에 부착되어 어떤 종류의 Swing 컴포넌트든지 그 컴포넌트의 가장자리를 어떻게 그려야 할지 정의한다. 테두리는 GUI 컴포넌트들이 어떻게 조직되었는가에 대한 시각적 단서를 제공하는데 사용된다 BorderFactory 클래스는 테두리 객체를 생성하기 위한 몇 개의 static 메쏘드를 갖고 있다 테두리는 컴포넌트의 setBorder() 메쏘드를 사용하여 컴포넌트에 적용된다

142 테두리(Borders)의 종류 공백 테두리(empty border) 선 테두리(line border)
컴포넌트의 가장자리 바깥쪽으로 여분의 공간을 만든다 그 외의 아무런 시각적 효과가 없다 선 테두리(line border) 단순한 선으로 컴포넌트를 둘러싼다 선의 색상과 두께는 임의로 설정할 수 있다 식각 테두리(etched border ) 컴포넌트의 둘레에 식각 홈 효과를 낸다 식각의 밝고 어두운 곳의 색(color)을 지정할 수 있다 용어: 식각(蝕刻) - 약물 등을 써서 부식시켜 깎아내는 것

143 테두리(Borders)의 종류 경사 테두리(bevel border) 제목 테두리(titled border)
솟거나 꺼질 수 있다 바깥쪽이나 안쪽의 밝고 어두운 곳의 각 경사면 색을 지정할 수 있다 제목 테두리(titled border) 테두리 위나 둘레에 제목을 둔다 제목 방향은 여러 가지로 지정될 수 있다 장식 테두리(matte border) 테두리의 상하좌우 가장자리의 크기를 각기 지정할 수 있다 가장자리들은 단일 색상으로 이루어질 수도 있고 혹은 이미지를 사용할 수도 있다

144 테두리(Borders)의 종류 복합 테두리(compound border)
두 개 테두리의 조합 복합 테두리 중의 하나 또는 둘 모두 다시 복합 테두리일 수도 있다 BorderDemo.java (국,영: 355쪽) 참조

145 BorderDemo.java //******************************************************************** // BorderDemo.java Authors: Lewis/Loftus // Demonstrates the use of various types of borders. import java.awt.*; import javax.swing.*; import javax.swing.border.*; public class BorderDemo { // // Creates several bordered panels and displays them. public static void main (String[] args) JFrame frame = new JFrame ("Border Demo"); frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);

146 BorderDemo.java (cont’d)
JPanel panel = new JPanel(); panel.setLayout (new GridLayout (0, 2, 5, 10)); panel.setBorder (BorderFactory.createEmptyBorder (8, 8, 8, 8)); JPanel p1 = new JPanel(); p1.setBorder (BorderFactory.createLineBorder (Color.red, 3)); p1.add (new JLabel ("Line Border")); panel.add (p1); JPanel p2 = new JPanel(); p2.setBorder (BorderFactory.createEtchedBorder ()); p2.add (new JLabel ("Etched Border")); panel.add (p2); JPanel p3 = new JPanel(); p3.setBorder (BorderFactory.createRaisedBevelBorder ()); p3.add (new JLabel ("Raised Bevel Border")); panel.add (p3);

147 BorderDemo.java (cont’d)
JPanel p4 = new JPanel(); p4.setBorder (BorderFactory.createLoweredBevelBorder ()); p4.add (new JLabel ("Lowered Bevel Border")); panel.add (p4); JPanel p5 = new JPanel(); p5.setBorder (BorderFactory.createTitledBorder ("Title")); p5.add (new JLabel ("Titled Border")); panel.add (p5); JPanel p6 = new JPanel(); TitledBorder tb = BorderFactory.createTitledBorder ("Title"); tb.setTitleJustification (TitledBorder.RIGHT); p6.setBorder (tb); p6.add (new JLabel ("Titled Border (right)")); panel.add (p6);

148 BorderDemo.java (cont’d)
JPanel p7 = new JPanel(); Border b1 = BorderFactory.createLineBorder (Color.blue, 2); Border b2 = BorderFactory.createEtchedBorder (); p7.setBorder (BorderFactory.createCompoundBorder (b1, b2)); p7.add (new JLabel ("Compound Border")); panel.add (p7); JPanel p8 = new JPanel(); Border mb = BorderFactory.createMatteBorder (1, 5, 1, 1, Color.red); p8.setBorder (mb); p8.add (new JLabel ("Matte Border")); panel.add (p8); frame.getContentPane().add (panel); frame.pack(); frame.setVisible(true); } top, left, bottom, right

149 요약 6장에서 살펴 본 주요 내용: 소프트웨어 개발 과정 프로그램에 필요한 클래스와 객체의 결정 클래스 사이의 관계
static 조정자(static modifier) 인터페이스 작성 열거 타입(enumerated type) 클래스의 설계 메쏘드 설계와 메쏘드 중복정의 GUI 설계와 레이아웃 관리자(layout managers)


Download ppt "객체 지향 설계 Object-Oriented Design"

Similar presentations


Ads by Google