







각 객체가 자료구조를 가진다는 것은 각 객체가 어떤 속성을 가지고 있따는 것을 의미
각 객체가 적용될 수 있는 연산을 갖는다는 것은 각 객체가 어떤 연산을 수행할 수 있는 능력을 갖고 있다는 의미





적용:
➡️ 결론: 상속은 무조건 하는 게 아니라, 더 면밀하게 분석하고 역할을 쪼개서 설계해야 한다.
즉, Rectangle 자리에 Square를 넣었더니 결과가 바뀜

클래스 다이어그램은 UML 다이어그램 중에서 가장 대표적인 정적 다이어그램.



상속과 인터페이스만 잘 표현되어 있으면 된다.
Transcirpt는 여러 Registration의 객체이다. 방향을 조심하자. Transcript가 소스이다.


객체 이름: 클래스 이름 형식으로 표현한다.프레임에 엮어서 표현해주면 된다.


도서관 시스템에서 책의 상태


Business Process Execution Language(정식으론 WS-BPEL)
POP는 위협을 발견하면 제약을 추가해서 충돌을 해결한다.
유스케이스 다이어그램 ↔ 시퀀스 다이어그램: 유스케이스 명세가 있고 매칭되는 시퀀스가 있는지

시퀀스 다이어그램 ↔ 클래스 다이어그램: 시퀀스에 등장한 클래스/메시지가 클래스 다이어그램에 누락되지 않았는지

상태 다이어그램 ↔ 클래스 다이어그램: 두 모델 간 크로스체크

기본 미션: 다음의 모바일기기 기반 지하철 출입 및 결제 시스템의 기능을 모델링하는 클래스 다이어그램과 시퀀스 다이어그램을 작성하시오.
MobileApp 클래스가 TicketGate 클래스에 사용자의 ID를 전달
TicketGate 클래스가 SeoulMetro에 다음의 정보를 전달
사용자 ID
태그 시각
역 이름
들어가는 경우 위의 3가지 정보만 전달
나가는 경우 사용자 ID, 태그 시각, 역 이름 전달하고, 요금 계산 요청
입력 또는 하역인 경우에 따른 로직이 달라지므로 이는 StarUML toolbox -> Interaction (Advanced) 에서 Combined Fragment라는 프레임을 이용해서 표현하도록 한다. Combined Fragment에 Operand를 추가하여 두가지의 경우를 처리하는 로직을 표현한다. interactionOperator는 "alt"로 지정한다. Combined Fragment는 두개의 다른 로직이 일어나는 시퀀스 다이어그램의 부분들을 감싸도록 표현한다.
SeoulMetro는 사용자 ID, 요금 및 요청 시각을 보낸다
CardPayment는 정산 완료 후 사용자 ID, 요금 및 처리 시각을 DB에 저장한다.
산출물
모델들이 담긴 PDF 파일 (File -> Print to (Save as) PDF) (하나의 파일로 제출)
(보너스) 생성형 AI에 의해 생성된 코드 (아무 선호하는 언어)
유의 사항:
추가 미션 1:
Interaction Overview Diagram 기능을 사용하여, State Chart Diagram의 Decision 등을 써서 들어갈 때와 나올때의 로직을 구분해서 모델링
(들어갈 때의 로직과 나올때의 로직을 Interaction (Inline) 을 이용하여 별도의 시퀀스 다이어그램으로 그리고) 초기 조건에서 들어갈때와 나올때를 구분하여 어떤 시퀀스 다이어그램을 선택할지를 결정.
이 경우 기본 미션에서 썼던 Combined Fragment는 쓰지 않는 것으로 함 (쓸 필요가 굳이 없음)
Interaction Overview Diagram을 통한 State Chart Diagram과 시퀀스 다이어그램의 혼용 방법은 다음의 메뉴얼에서 참고하도록 한다.
https://docs.staruml.io/working-with-uml-diagrams/interaction-overview-diagram
https://drawio-app.com/blog/uml-interaction-overview-diagrams-in-draw-io/
추가 미션2:
모델링된 것을 ChatGPT 등의 생성형 AI에 넣어서 모델을 구현한 코드를 생성해달라고 해보자. 그리고, 어떤 결과가 나오는지 분석해보자.
TA (강의조교)들이 여러분들 실습을 봐줄테니, 많은 도움을 청하시기 바람.


import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
// MobileApp 클래스
class MobileApp {
private String userId;
public MobileApp(String userId) {
this.userId = userId;
}
public String getUserId() {
return userId;
}
public void sendUserId(TicketGate gate, boolean isEntry) {
LocalDateTime tagTime = LocalDateTime.now();
if (isEntry) {
gate.processTagEntry(userId, tagTime);
} else {
gate.processTagExit(userId, tagTime);
}
}
}
// TicketGate 클래스
class TicketGate {
private String stationName;
private SeoulMetro seoulMetro;
public TicketGate(String stationName, SeoulMetro seoulMetro) {
this.stationName = stationName;
this.seoulMetro = seoulMetro;
}
public void processTagEntry(String userId, LocalDateTime tagTime) {
seoulMetro.recordEntry(userId, tagTime, stationName);
}
public void processTagExit(String userId, LocalDateTime tagTime) {
int fare = seoulMetro.calculateFare(userId, tagTime, stationName);
seoulMetro.requestPayment(userId, fare, tagTime);
}
}
// SeoulMetro 클래스
class SeoulMetro {
// 사용자별 입장 기록 저장
private Map<String, EntryRecord> entryRecords = new HashMap<>();
private CardPayment cardPayment;
public SeoulMetro(CardPayment cardPayment) {
this.cardPayment = cardPayment;
}
public void recordEntry(String userId, LocalDateTime tagTime, String stationName) {
entryRecords.put(userId, new EntryRecord(tagTime, stationName));
System.out.println("[SeoulMetro] 승차 기록 저장");
System.out.println("사용자 ID: " + userId);
System.out.println("태그 시각: " + tagTime);
System.out.println("역 이름: " + stationName);
System.out.println();
}
public int calculateFare(String userId, LocalDateTime exitTime, String exitStation) {
EntryRecord entry = entryRecords.get(userId);
System.out.println("[SeoulMetro] 요금 계산 요청");
System.out.println("사용자 ID: " + userId);
System.out.println("하차 시각: " + exitTime);
System.out.println("하차 역: " + exitStation);
if (entry == null) {
System.out.println("승차 기록이 없어 기본 요금 0원 처리");
System.out.println();
return 0;
}
// 예시용 고정 요금
int fare = 1500;
System.out.println("승차 역: " + entry.getStationName());
System.out.println("계산된 요금: " + fare + "원");
System.out.println();
return fare;
}
public void requestPayment(String userId, int fare, LocalDateTime requestTime) {
System.out.println("[SeoulMetro] 결제 요청");
System.out.println("사용자 ID: " + userId);
System.out.println("요금: " + fare + "원");
System.out.println("요청 시각: " + requestTime);
System.out.println();
cardPayment.settlePayment(userId, fare, requestTime);
}
}
// CardPayment 클래스
class CardPayment {
private DB db;
public CardPayment(DB db) {
this.db = db;
}
public void settlePayment(String userId, int fare, LocalDateTime requestTime) {
LocalDateTime processedTime = LocalDateTime.now();
System.out.println("[CardPayment] 결제 정산 완료");
System.out.println("사용자 ID: " + userId);
System.out.println("요금: " + fare + "원");
System.out.println("요청 시각: " + requestTime);
System.out.println("처리 시각: " + processedTime);
System.out.println();
savePaymentHistory(userId, fare, processedTime);
}
public void savePaymentHistory(String userId, int fare, LocalDateTime processedTime) {
db.savePayment(userId, fare, processedTime);
}
}
// DB 클래스
class DB {
public void savePayment(String userId, int fare, LocalDateTime processedTime) {
System.out.println("[DB] 결제 내역 저장 완료");
System.out.println("사용자 ID: " + userId);
System.out.println("요금: " + fare + "원");
System.out.println("처리 시각: " + processedTime);
System.out.println();
}
}
// 승차 기록 저장용 클래스
class EntryRecord {
private LocalDateTime tagTime;
private String stationName;
public EntryRecord(LocalDateTime tagTime, String stationName) {
this.tagTime = tagTime;
this.stationName = stationName;
}
public LocalDateTime getTagTime() {
return tagTime;
}
public String getStationName() {
return stationName;
}
}
// 실행 예시
public class SubwaySystemDemo {
public static void main(String[] args) {
DB db = new DB();
CardPayment cardPayment = new CardPayment(db);
SeoulMetro seoulMetro = new SeoulMetro(cardPayment);
TicketGate gangnamGate = new TicketGate("Gangnam", seoulMetro);
TicketGate cityHallGate = new TicketGate("CityHall", seoulMetro);
MobileApp app = new MobileApp("user123");
// 입장
app.sendUserId(gangnamGate, true);
// 퇴장
app.sendUserId(cityHallGate, false);
}
}