10장. 종합하기

:D 이제 여러분들은 책을 정리할때가 다가왔습니다. 마지막 까지 잘 해봅시다.

  1. 10장. 종합하기
    1. 10.1 OOA&D 스타일로 소프트웨어 개발하기
    2. 10.2 객체마을 여행길라잡이 소프트웨어 개발하기

10.1 OOA&D 스타일로 소프트웨어 개발하기

책의 전체 내용을 뭉뚱그려서 여지껏 배워온 흐름대로 개발을 진행 합니다.
개발 흐름은 다음과 같습니다.

OOAD 스타일 개발 순서

1. 특징리스트 : 상위 수준에서의 애플리케이션 동작에 대한 이해
2. 유스케이스다이어그램 : 수행될 프로세스와 외부영향에 대한 결정
3. 문제점 분해하기 : 기능단위인 모듈로 분해하여 어떤걸 먼저 할지 순서 결정
4. 요구사항 : 각 모듈에 대한 개별적 요구 사항을 이해하고 큰 그림 만들기
5. 도메인 분석 : 어떻게 유스케이스 들이 애플리케이션의 객체들로 사상되는지 이해하고 공감대 형성
6. 사전설계 : 객체들에 대한 세부 내용을 채워 넣고 객체간에 패턴을 적용
7. 구현 : 코드를 작성 하고 테스트 하여 동작하는걸 확인하고 완성한다.(지속적 테스팅 TDD 구현)
8. 출하 : 잔금수거 하기 :D

ps.
사전설계와 구현 부분에서는 OOP언어의 특성을 최대한 발휘 해서 정형화된 패턴을 찾아 최대한 유연하게 개발 합시다.
그래여 유지보수가 쉬워지고 재사용 하기 편해지니까요. 이건 정말 중요해요. 제대로 안될경우에는 잔금 수거가 힘들어지니까요.
회사가 망할수도 있어요. 갑이 계속 트집을 잡거든요.

10.2 객체마을 여행길라잡이 소프트웨어 개발하기

책 524 페이지를 보시면 우리가 만들어야할 프로젝트의 요구사항 명세서를 간단한 작업기술서 형태로 제공 하고 있네요
한번 살펴 보고 갑시다.

START! 객체마을 지하철 노선도

10.2.1 특징리스트, 유스케이스 다이어그래, 문제점 분석하기 , 요구사항, 도메인 분석

특징

보통 하나의 특징을 만족시키기 위해서는 서너개의 요구 사항이 필요할수 있습니다.
유즈케이스 다이어그램을 통해서 하나의 특징 리스트를 어떻게 세부 항목과 구분하는 확인해 봅시다

객체마을 지하철 노선도 의 특징리스트는 다음과 같습니다.

1. 지하철 노선의 역들을 표시하기
2. 겹쳐진 노선을 포함하여 다수의 지하철 노선을 적재하기
3. 두 역 사이의 유효한 경로를 찾기
4. 두 역 사이에 있는 특정 경로의 방향 표시 출력하기

  • 특징리스트
    • 특징리스트는 소프트 웨어가 무엇을 해야하는지 이해 하는 것입니다.
    • 유스케이스 다이어그램을 이용하여 세부항목이 아닌 핵심을 볼수 있게 표현 합니다.
  • 유스케이스 다이어그램

    특징
    1.유스케이스는 사용법을 반영하고, 특징은 기능을 반영합니다.
    2.시스템의 특징은 시스템이 기능을 나타냅니다. 비록 기능이 항상 어떤 특정 유스케이스의 눈에 드러난
    일부는 아니지만, 시스템은 유스케이스가 실제로 작동하기 위해서 이러한 것들을 해야 합니다.
    3.시스템에서 특징은 시스템이 해야하는 것이며 시스템이 어떻게 사용되어야 하는지 보여주는 유스케이스에 항상
    반영되지는 않습니다.
    4.특징과 유스케이스는 함께 작업합니다. 그러나 그것들이 같은것은 아닙니다.

그림들어갈 위치

  • 문제점 분해하기(위의 유스케이스 다이어그램을 통해서 작은 단위의 기능으로 분리하고 각기능에대해 지속적으로 테스트 해야 합니다.)
    • 1.Subway : 지하철 모듈은 역과 각 역 사이의 연결, 전체 지하철 시스템을 나타내는 모든 코드를 가지고 있습니다. 그리고 또다른 역으로 가는 길을 찾는 방법을 알고 있습니다.
      • 역 : 이름있는 지도위의 점
      • 노선: 역 과 역 사이의 연결이라 하면 연결의 조합이 노선
    • 2.Loader : 지하철을 적재하는 여러가지 방법(파일 , 사용자 입력, 데이터 베이스 )이 있습니다. 적재는 실제 지하철을 표시하는 것과는 구분이 됩니다. 그래서 그것으 자신의 모듈을 가지고 있습니다.
    • 3.Printer: 인쇄는 적재와 매우 비슷합니다. 그것은 자히철 시스템 그자체와는 구분이 됩니다. 이것은 지하철을 어떤기기나. 필요한 형식으로 인새하는 것을 다룹니다.
    • 4.Test : 테스트는 시스템의 밖에서 시스템과 상호 작용 합니다.

1.Subway
1.1 Subway 표시하기에 대한 정의

1.2 요구사항

  • p.542 참조

1.3 유스케이스 동작여부 검증

  • p.544. p.545

1.4 분석과 설계

  • 유스케이스로부터 명사와 동사를 구분해 클래스와 메소드를 추출 합니다.(사전설계 작업) p.548

10.2.2 사전설계

지하철 노선 적재하기 유스케이스

1.관리자가 역과 노선이 담긴 파일을 공급한다.
2.시스템은 역의 이름을 읽어 온다.
3.시스템은 역이 이미 존재하지 않는지 검증한다.
4.시스템은 지하철에 새로운 역을 추가한다.
5.시스템은 모든 역이 추가될 때까지 단계 2~4를 반복한다.
6.시스템은 추가할 노선의 이름을 읽어 들인다.
7.시스템은 연결되어 있는 두 역을 읽어 들인다.
8.시스템은 역들이 존재하는지 검증한다.
9.시스템은 현재 노선의 두 역 사이에 양방향으로 진행 가능한 새로운 연결을 생성한다.
10.시스템은 노선이 완선될 때까지 단계 7~9를 반복한다.
11.시스템은 모든 노선이 입력될 ?까지 단계 6~10을 반복한다.

  • 명사 와 동사를 통해 클래스와 메소드를 추출해내고 관계를 맺어 봅니다. p.548. p.549

10.2.3 구현

Station.javaConnection.javaSubway.java
{code}
package com.oracleclub.study.ooad.ten;
public class Station {
private String name;

public Station(String name) {
this.name =name;
}

public String getName() {
return name;
}

public boolean equals(Object obj) {

if (obj instanceof Station) {
Station otherStation = (Station) obj;
if (otherStation.getName().equalsIgnoreCase(name)) {
return true;
}
}

return false;
}

public int hashCode() {
return name.toLowerCase().hashCode();
}

}

|

package com.oracleclub.study.ooad.ten;

public class Connection {

private Station station1, station2;
private String lineName;

public Connection (Station station1, Station station2, String lineName) {
this.station1 = station1;
this.station2 = station2;
this.lineName = lineName;
}

public Station getStation1() {
return station1;
}

public Station getStation2() {
return station2;
}

public String getLineName() {
return lineName;
}
}

|

package com.oracleclub.study.ooad.ten;

import java.util.LinkedList;
import java.util.List;

public class Subway {
private List stations;
private List connections;

public Subway () {
this.stations = new LinkedList();
this.connections = new LinkedList();
}

public void addStation(String stationName) {
if (!this.hasStation(stationName)) {
Station station = new Station(stationName);
stations.add(station);
}
}

private boolean hasStation(String station2) {
// TODO Auto-generated method stub
return stations.contains(new Station(station2));
}

public void addConnection(String stationName1,
String stationName2,
String lineName) {
if ((this.hasStation(stationName1)) &&
(this.hasStation(stationName2))) {

Station station1 = new Station(stationName1);
Station station2 = new Station(stationName2);
Connection connection = new Connection(station1, station2, lineName);
connections.add(connection);
connections.add(new Connection(station2, station1, connection.getLineName()));
}else {
throw new RuntimeException("Invalid connection");
}
}
}

|

|| SubwayLoader.java ||Subway.java||
|

package com.oracleclub.study.ooad.ten;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class SubwayLoader {

private Subway subway;

public SubwayLoader(){
this.subway = new Subway();
}

public Subway loadFromFile(File subwayFile) throws IOException {
BufferedReader reader = new BufferedReader(
new FileReader(subwayFile)
);

loadStations(subway, reader);
String lineName = reader.readLine();

while ((lineName != null) && (lineName.length() > 0)) {
loadLine(subway, reader, lineName);
}

return subway;
}

private void loadStations(Subway subway2, BufferedReader reader) throws IOException{
// TODO Auto-generated method stub
String currentline;
currentline = reader.readLine();
while (currentline.length() > 0) {
subway2.addStation(currentline);
currentline = reader.readLine();
}
}

private void loadLine(Subway subway, BufferedReader reader, String lineName) throws IOException{
String stationName1, stationName2;
stationName1 = reader.readLine();
stationName2 = reader.readLine();

while ((stationName2!= null) && (stationName2.length() > 0)) {
subway.addConnection(stationName1, stationName2, lineName);
stationName1 = stationName2;
stationName2 = reader.readLine();
}
}}

|

|

import java.util.*;

public class Subway
{
private List stations;
private List connections;
private Map network;

public Subway() {
this.stations = new LinkedList();
this.connections = new LinkedList();
this.network = new HashMap();
}

public void addStation(String stationName) {
if (!this.hasStation(stationName)) {
Station station = new Station(stationName);
stations.add(station);
}
}

public boolean hasStation(String stationName) {
return stations.contains(new Station(stationName));
}

public void addConnection(String station1Name, String station2Name, String lineName) {
if ((this.hasStation(station1Name)) && (this.hasStation(station2Name))) {
Station station1 = new Station(station1Name);
Station station2 = new Station(station2Name);
Connection connection = new Connection(station1, station2, lineName);
connections.add(connection);
connections.add(new Connection(station2, station1, connection.getLineName()));

addToNetwork(station1, station2);
addToNetwork(station2, station1);
}
else
{
throw new RuntimeException("Invalid connection: " + station1Name + ", " + station2Name + ", " + lineName + "");
}
}

private void addToNetwork(Station station1, Station station2) {
if (network.keySet().contains(station1)) {
List connectingStations = (List) network.get(station1);
if (!connectingStations.contains(station2)) {
connectingStations.add(station2);
}
} else {
List connectingStations = new LinkedList();
connectingStations.add(station2);
network.put(station1, connectingStations);
}
}

public List getDirections(String startStationName, String endStationName) {
if (!this.hasStation(startStationName) || !this.hasStation(endStationName))
{
throw new RuntimeException("Stations entered do not exist on this subway");
}

Station start = new Station(startStationName);
Station end = new Station(endStationName);
List route = new LinkedList();
List reachableStations = new LinkedList();
Map previousStations = new HashMap();
List neighbors = (List)network.get(start);

for (Iterator i = neighbors.iterator(); i.hasNext(); ) {
Station station = (Station) i.next();
if (station.equals(end)) {
route.add(getConnection(start, end));
return route;
} else {
reachableStations.add(station);
previousStations.put(station, start);
}
}

List nextStations = new LinkedList();
nextStations.addAll(neighbors);
Station currentStation = start;

searchLoop:
for (int i = 1; i < stations.size(); i++) {
List tmpNextStations = new LinkedList();
for (Iterator j = nextStations.iterator(); j.hasNext(); ) {
Station station = (Station) j.next();
reachableStations.add(station);
currentStation = station;
List currentNeighbors = (List) network.get(currentStation);
for (Iterator k = currentNeighbors.iterator(); k.hasNext(); ) {
Station neighbor = (Station) k.next();
if (neighbor.equals(end)) {
reachableStations.add(neighbor);
previousStations.put(neighbor, currentStation);
break searchLoop;
} else if (!reachableStations.contains(neighbor)) {
reachableStations.add(neighbor);
tmpNextStations.add(neighbor);
previousStations.put(neighbor, currentStation);
}
}
}
nextStations = tmpNextStations;
}

//We've found the path now!
boolean keepLooping = true;
Station keyStation = end;
Station station;

while (keepLooping) {
station = (Station) previousStations.get(keyStation);
route.add(0, getConnection(station, keyStation));
if (start.equals(station)) {
keepLooping = false;
}
keyStation = station;
}

return route;
}

private Connection getConnection(Station station1, Station station2) {
for (Iterator i = connections.iterator(); i.hasNext(); ) {
Connection connection = (Connection) i.next();
Station one = connection.getStation1();
Station two = connection.getStation2();
if ((station1.equals(one)) && station2.equals(two)) {
return connection;
}
}
return null;
}

public boolean hasConnection(String station1Name, String station2Name, String lineName) {
Station station1 = new Station(station1Name);
Station station2 = new Station(station2Name);
for (Iterator i = connections.iterator(); i.hasNext(); ) {
Connection connection = (Connection) i.next();
if (connection.getLineName().equalsIgnoreCase(lineName)) {
if ((connection.getStation1().equals(station1)) &&
(connection.getStation2().equals(station2)))
{
return true;
}
}
}
return false;
}

}

|


위코드를 subversion을 통해서 동기화 한다음에 테스트 해보시고 결과를 확인해 보시기 바랍니다. ( package com.oracleclub.study.ooad.ten )

위 작업을 통해서 *지하철 노선 적재하기* 라는 유스케이스를 완성 하였습니다. 다음은
*길찾기* 유스케이스를 작성하기 위해 요구사항 단계로 돌아가서 지금까지 한 내용을 반복 합니다.
같은 단계를 거치므로 생략 하고 각 단계에서 발생될수 있는 의문사항에 대해 살펴보고 마무리 하도록 하겠습니다.

다익스트라알고리즘 !1.GIF! * 1. 맨처음 S에서 갈 수 있는 곳들을 처음 S에서 갈수있는 최단거리로 놓는다. * 2. S에서 모든 정점중 가장 거리가 짧은 정점을 구한다.(여짓것 구한 것들을 토대로) 만약 그 정점을 X라고 하면, 현제 구한 S~>X는 S에서 X까지 가는 최단거리이다. * 3. X를 경유하여 (S~>X + X->Y) < (S~>Y)라고 한다면, S~>Y를 X를 경유한 S~X + X->Y로 대체한다. * 4. 2번부터 다시 반복한다.( n-1번 ) !1214581885720.gif!

h3. 10.2.4 출하 돈받아야지요. h2. 10.3 정리하기 h2. 문서에 대하여 * 이 문서는 [Head First Object-Oriented Analysis & Design|http://book.naver.com/bookdb/book_detail.php?bid=2920750]을 정리한 내용 입니다. * 이 문서는 [오라클클럽|http://www.gurubee.net] [자바 웹개발자 스터디|제3차 자바 웹개발자 스터디] 모임에서 작성하였습니다. * 이 문서를 다른 블로그나 홈페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^\^