푸터 콘텐츠로 바로가기
Iron Academy Logo
C# 애플리케이션
C# 애플리케이션

다른 카테고리

C# 인터페이스: 상금 폼 연결 이해하기 (Tim Corey, 레슨 09)

Tim Corey
1h 27m 22s

Tim Corey의 "C# App Start To Finish" 시리즈에서, Lesson 09는 상 양식 연결에 중점을 둡니다. 표면적으로 이 양식은 간단해 보입니다. 사용자 입력을 수집하고, 이를 검사하며, 모델을 생성하고 저장하는 것입니다. 하지만 Tim은 실제 복잡성은 데이터를 어디에 저장할지를 결정하는 데 있다고 설명합니다. Tim의 비디오에서는 C# 프로그래밍의 핵심 개념을 소개하면서 솔루션을 안내합니다: 인터페이스.

이 기사에서는 Tim의 설명을 통해 인터페이스를 더 깊이 이해할 수 있도록 하여 확장 가능하고 유지 관리가 가능한 응용 프로그램 제작에 도움이 될 수 있도록 할 것입니다.

문제: 데이터를 어디에 저장합니까?

Tim은 상 폼의 목적을 말하며, 이는 입력을 받고, 검증하며, 저장소에 저장한다고 설명합니다. 그러나 그는 데이터를 저장할 위치를 결정하는 것이 어려운 부분이라고 경고합니다. 그는 튜토리얼들이 종종 이것을 쉽게 지나치지만, 학습자가 직접적으로 도전하길 원한다고 강조합니다.

그는 처음에는 간단한 해결책을 시도할 수 있다고 설명합니다: SQL을 사용하고 있는지 아니면 텍스트 파일을 사용하고 있는지 확인한 다음 올바른 저장 과정을 수행합니다. 하지만 Tim은 그것이 얼마나 못생기고 유지보수할 수 없는 모습을 금방 보여줍니다. 모든 폼이 사용해야 할 저장소 유형을 확인해야 한다면, 코드는 중복되며 지저분하고 수정하기 어려워집니다.

못난 방법: 하드코드된 조건

Tim은 의사 코드 예제를 스케치 제공합니다. 그는 usingSQL == true와 같은 부울 값을 확인한 다음 데이터베이스 연결을 열고, 모델을 저장한 후 ID와 함께 반환할 수 있다고 설명합니다. 그런 다음 텍스트 파일에도 동일한 작업을 수행하며, 텍스트 파일은 자동으로 ID를 생성하지 않기 때문에 수동으로 ID를 생성해야 할 수 있습니다.

그는 이것이 빠르게 반복적이 된다고 지적하며, 여러 폼이 이러한 논리를 필요로 하며, MySQL과 같은 새로운 데이터 소스를 추가할 때마다 모든 폼을 업데이트해야 한다고 합니다. Tim은 이것이 "확장 가능하지 않다"고 말하며 "DRY(반복하지 마라)" 원칙을 위반한다고 강조합니다. 그는 분명히 말합니다: "더 나은 방법이 있어야 한다."

실마리를 잡아당기기: 더 나은 접근법

Tim은 그의 전략을 소개합니다: 실마리를 잡아당기기. 그는 코드가 필요한 정보가 무엇인지, 어디에서 오는지 묻는 것부터 시작합니다. 그는 두 가지 핵심 질문을 식별합니다:

어떤 데이터 소스를 사용할지 어떻게 알 수 있을까요?

같은 작업을 하기 위해 두 개의 다른 데이터 소스에 어떻게 연결할까요?

팀은 실제로 저장하는 행위만이 다르다고 설명합니다. 폼의 관점에서, 단지 이렇게 말하면 됩니다: "여기 모델이 있습니다. 저장하십시오." 폼은 SQL로 저장하든 텍스트 파일로 저장하든 상관하지 않아야 합니다.

해결책: 글로벌 구성 + 인터페이스

팀은 글로벌 구성 시스템을 제안합니다. 그는 어떤 데이터 소스를 사용할지 알기 위해서, 애플리케이션이 전역적으로 접근할 수 있는 데이터가 필요하며 이 정보를 저장하기 위해 정적 클래스를 사용할 것을 제안합니다. 그는 전역 변수를 보통 피하지만, 이 경우에는 전역 데이터가 필요한 것이라고 인정합니다.

다음으로, 팀은 핵심 개념인 인터페이스를 설명합니다. 그는 인터페이스를 계약으로 정의하며, 이를 구현하는 클래스가 특정 메서드나 속성을 포함할 것을 약속합니다. 팀은 이를 통해 애플리케이션이 데이터 소스에 상관없이 동일한 메서드를 호출할 수 있다고 강조합니다. 폼은 SQL인지 텍스트 파일인지 신경 쓰지 않으며, 단지 메서드를 호출하는 것에만 신경 씁니다.

팀은, "같은 작업을 해야 하지만 장면 뒤에서는 두 가지 다른 방법으로 수행된다면 인터페이스가 필요하다"고 말합니다.

인터페이스 만들기

팀은 Tracker Library에서 인터페이스를 만들어 실제 구현으로 이동합니다. 그는 이를 IDataConnection이라 명명하고 인터페이스 앞에 'I'를 붙이는 관습을 설명합니다. 이는 인터페이스로 명확하게 식별하는 데 중요하다고 강조합니다.

팀은 인터페이스에 단일 메서드를 추가합니다:

PrizeModel CreatePrize(PrizeModel model);

그는 이 메서드가 계약이며, IDataConnection을 구현하는 모든 클래스에 존재해야 한다고 설명합니다. 폼은 이 메서드를 호출하고 ID가 있는 PrizeModel을 반환받을 것으로 기대합니다. 팀은 이를 통해 폼이 저장소 유형에 무관하게 유지된다고 설명합니다.

글로벌 구성 정적 클래스 만들기

다음으로, 팀은 GlobalConfig라는 정적 클래스를 만듭니다. 그는 정적 클래스는 인스턴스화할 수 없고 전역적으로 접근할 수 있다고 설명합니다. 여기는 애플리케이션이 사용 가능한 데이터 연결 목록을 저장할 곳입니다.

그는 속성을 정의합니다:

public static List<IDataConnection> Connections { get; private set; }

팀은 오직 클래스 자체만 리스트를 수정할 수 있도록 하기 위해 private set을 사용한 것을 설명합니다. 애플리케이션의 다른 부분은 읽기만 할 수 있습니다.

그는 그런 다음 메서드를 만듭니다:

public static void InitializeConnections(bool database, bool textFiles)

이 메서드는 사용 가능한 데이터 연결을 설정합니다. 팀은 이 리스트가 여러 연결을 허용하여, 애플리케이션이 SQL, 텍스트 파일, 또는 둘 다에 저장할 수 있음을 강조합니다.

인터페이스 이해하기: 실제 예

팀은 이 복잡한 자료가 달성 가능하지만 복잡하다는 것을 학습자들에게 안심시킵니다. 그는 비디오를 한 번 보고 코드를 함께 짜면서 다시 시청할 것을 권장합니다.

인터페이스가 계약이며, 이를 구현하는 클래스가 계약을 따라야 한다고 설명합니다. 그는 IDataConnection을 구현하는 SQLConnector 클래스를 생성하여 이를 보여줍니다.

클래스가 생성되었을 때, Visual Studio는 계약이 충족되지 않았다고 경고합니다. 팀은 'Implement Interface'를 사용하여 자동으로 CreatePrize 메서드를 생성하는 방법을 보여줍니다. 그리고 NotImplementedException 스캐폴드와 그 이유를 설명합니다. 이것은 메서드가 작동한다고 주장하지 않고도 코드를 컴파일 할 수 있게 해줍니다.

SQL 및 텍스트 연결기 만들기

팀은 SQLConnector 클래스와 TextConnector 클래스를 추가하며, 둘 다 IDataConnection을 구현합니다. 그는 SQL 데이터베이스에 저장하는 것과 텍스트 파일에 저장하는 것이 매우 다른 과정이지만, 둘 다 동일한 인터페이스 계약을 만족시킨다고 설명합니다.

그는 지금은 간단한 샘플 반환 값을 추가하고 나중에 실제 저장 로직을 구현하라는 TODO 주석을 추가합니다. 이는 애플리케이션을 기능적으로 유지하면서도 수업을 진행할 수 있게 합니다.

최종 설정: 글로벌 구성 연결

팀은 GlobalConfig 클래스에 돌아가 실제 연결을 설정합니다. 그는 Connections 리스트를 초기화하고 SQLConnector와 TextConnector의 인스턴스를 추가하는 방법을 보여줍니다.

그는 왜 두 개의 별도 if 문이 필요한지 설명합니다 - 사용자가 두 가지 소스에 동시에 저장하고자 할 수 있기 때문입니다.

InitializeConnections를 어디에 호출할까요?

팀은 InitializeConnections가 애플리케이션 시작 시 호출되어야 함을 설명합니다. 그는 Program.cs를 수정하고 다음을 호출합니다:

GlobalConfig.InitializeConnections(true, true);

폼을 시작하기 전에. 이는 연결 목록이 애플리케이션 전반에서 준비되고 접근 가능하도록 보장합니다.

그는 그런 다음 시작 폼을 CreatePrizeForm으로 변경하여 즉시 기능을 테스트 할 수 있습니다.

상금 폼 검증

팀은 폼을 열고 첫 번째 작업을 설명합니다: 네 가지 필드를 검증하는 것입니다. 그는 이벤트 핸들러를 깔끔하게 유지하고 싶어, ValidateForm이라는 개인 메서드를 만듭니다.

팀은 이 메서드가 버튼 클릭뿐만 아니라 어디서든 호출될 수 있다고 설명합니다. 이는 폼이 유효한지 여부를 나타내는 Boolean을 반환합니다. 그는 출력 변수를 사용하는 자신의 패턴을 보여줍니다:

bool output = true; return output;

그는 처음에 true로 시작하는 것이 좋다고 말합니다. 이것은 무언가 잘못되었을 때 false로 변경하는 것이 더 쉬우며, 모든 검사를 진행한 후 true로 설정하는 것보다 더 낫다고 설명합니다.

장소 번호 확인

팀은 첫 번째 검증을 설명합니다: 장소 번호는 0보다 큰 정수여야 합니다.

그는 int.TryParse를 사용하여 PlaceNumberValue.Text (문자열)를 정수로 변환합니다. 팀은 TryParse가 어떻게 작동하는지 설명합니다:

  • 문자열을 받아 숫자로 변환하려고 시도합니다.

  • 성공 또는 실패를 나타내는 Boolean을 반환합니다.

  • 변환된 값을 출력하는 out 매개변수를 사용합니다.

팀은 TryParse가 잘못된 입력에서 충돌하지 않아 더 안전하며 거짓을 반환하고 출력을 0으로 설정한다고 강조합니다.

그는 그런 다음 논리를 설명합니다:

  • placeNumberValidNumber가 false인 경우, output = false로 설정합니다.

  • placeNumber < 1인 경우, output = false로 설정합니다.

팀은 이 메서드가 여러 가지 검사가 있기 때문에 여기서 else 문을 사용하는 것을 경고합니다. 하나의 검사가 실패하더라도 이 메서드는 모든 오류를 수집하기 위해 다른 모든 검사를 여전히 평가해야 합니다.

장소 이름 검증

팀은 다음 검증으로 넘어갑니다: 장소 이름은 비어 있을 수 없습니다.

그는 확인합니다:

if (placeNameValue.Text.Length == 0) { output = false; }

팀은 실제 애플리케이션에서는 각 실패한 검증에 대한 오류 메시지를 표시해야 한다고 설명합니다. 하지만 지금은 단순하게 유지하며 true/false만 반환합니다.

상금 금액 vs 상금 비율 검증

팀은 폼에 반드시 상금 금액 또는 상금 비율 중 하나는 포함되어야 하며 (둘 중 하나는 0보다 커야 함)라고 설명합니다. 그는 중요한 차이를 언급합니다:

  • 상금 비율은 전체 숫자 (int)입니다

  • 상금 금액은 소수 (decimal) 입니다, 왜냐하면 돈에는 센트가 포함될 수 있기 때문입니다.

그는 변수를 만듭니다:

decimal prizeAmount = 0; int prizePercentage = 0;

그런 다음 두 가지 모두에 TryParse를 사용합니다:

bool prizeAmountValid = decimal.TryParse(prizeAmountValue.Text, out prizeAmount); bool prizePercentageValid = int.TryParse(prizePercentageValue.Text, out prizePercentage);

팀은 둘 다 유효한 숫자여야 한다고 설명합니다. 둘 중 하나라도 유효하지 않으면 폼은 유효하지 않습니다.

다음으로, 적어도 하나가 0보다 큰지 확인합니다:

if (prizeAmount <= 0 && prizePercentage <= 0) { output = false; }

팀은 비율이 0과 100 사이인지 확인하는 검사를 추가합니다:

if (prizePercentage < 0||prizePercentage > 100) { output = false; }

그가 설명합니다: 150%는 상금 풀보다 더 많이 주는 것을 의미하므로 불가능합니다.

검증 결과 사용하기

모든 검사가 완료된 후, 팀은 결과를 사용하는 방법을 설명합니다:

if (ValidateForm()) { // 모델 생성 및 저장 } else { MessageBox.Show("이 폼에 잘못된 정보가 있습니다. 확인 후 다시 시도하십시오."); }

팀은 첫 번째 실패 시 일찍 반환할 수 있지만 모든 검사를 진행하여 사용자가 모든 검증 오류를 한 번에 볼 수 있도록 선택했다고 언급합니다. 이는 모든 것을 한 번에 수정할 수 있으므로 좌절감을 줄여줍니다.

PrizeModel 만들기

팀은 폼이 유효하면 다음 단계는 PrizeModel을 만드는 것이라고 설명합니다.

모델을 인스턴스화하는 방법을 보여줍니다:

PrizeModel model = new PrizeModel(); model.PlaceName = placeNameValue.Text; model.PlaceNumber = placeNumberValue.Text; // 문제: 이건 문자열입니다

팀은 문제점을 강조합니다: PlaceNumber는 int이지만 폼 값은 문자열입니다. 이를 해결하기 위해 두 가지 옵션을 설명합니다:

  • 폼 내에서 다시 각 값을 파싱 (반복적임).

  • PrizeModel에 생성자 오버로드 추가.

팀은 옵션 2를 선택합니다.

PrizeModel의 오버로드된 생성자

팀은 네 개의 문자열을 받는 오버로드된 생성자를 추가합니다:

public PrizeModel(string placeName, string placeNumber, string prizeAmount, string prizePercentage)
{
    PlaceName = placeName;
    PlaceNumber = int.TryParse(placeNumber, out int placeNumberValue) ? placeNumberValue : 0;
    PrizeAmount = decimal.TryParse(prizeAmount, out decimal prizeAmountValue) ? prizeAmountValue : 0;
    PrizePercentage = double.TryParse(prizePercentage, out double prizePercentageValue) ? prizePercentageValue : 0;
}

팀은 파싱이 실패하더라도 신경쓰지 않으며 자동으로 0으로 기본값을 설정한다고 설명합니다. 이는 어쨋든 숫자의 기본값이기 때문입니다.

이 생성자는 폼이 문자열 입력만으로 PrizeModel을 직접 생성하여 모델이 파싱을 처리할 수 있게 합니다.

IDataConnection을 사용한 모델 저장하기

이제 모델이 존재하므로, 팀은 글로벌 연결 목록을 사용하여 저장하는 방법을 설명합니다.

그는 foreach 루프를 사용합니다:

foreach (IDataConnection db in GlobalConfig.Connections) { db.CreatePrize(model); }

팀은 이 루프가 각 연결 (SQL과 텍스트 파일)에서 CreatePrize()를 호출한다고 설명합니다. 심지어 메서드가 아직 구현되지 않았더라도, 폼은 작동하고 데이터를 저장하는 척합니다. 이는 인터페이스와 글로벌 구성 패턴이 작동함을 증명합니다.

폼 테스트

팀은 조기 테스트의 중요성을 강조합니다. 그는 중단점을 추가하고 애플리케이션을 실행합니다.

  • 그는 먼저 빈 폼을 테스트합니다.

  • 그는 ValidateForm()을 단계별로 진행합니다.

  • 출력이 false이고 검증이 예상대로 실패하는 것을 확인합니다.

  • 그런 다음 유효한 데이터를 입력하고 생성자가 모델을 정확하게 채워주는 것을 확인합니다.

  • 그는 또한 루프가 두 연결을 모두 통해 실행됨을 확인합니다.

팀은 양식이 작동하며 패턴이 검증됨을 보여줍니다.

최종 정리: 양식 지우기

팀은 마지막으로 몇 가지 수정을 더합니다:

  • 상을 성공적으로 생성한 후, 양식 필드를 비웁니다.

  • 상금과 비율의 기본값을 0으로 설정하여 사용자가 매번 0을 입력할 필요가 없도록 합니다.

그는 유효한 제출 후 양식이 제대로 지워지는지 확인합니다.

다음에 할 일은?

팀은 SQL 및 텍스트 연결 클래스를 연결하여 실제로 데이터를 저장하게 만드는 것이 다음 단계라고 말하며 영상을 마칩니다.

그는 다음 수업에서는 SQL 커넥터를 구현하고 실제로 데이터베이스에 연결할 것임을 시청자들에게 상기시킵니다.

Hero Worlddot related to C# 인터페이스: 상금 폼 연결 이해하기 (Tim Corey, 레슨 09)
Hero Affiliate related to C# 인터페이스: 상금 폼 연결 이해하기 (Tim Corey, 레슨 09)

사랑하는 것을 공유하여 더 많은 수익을 얻으세요

당신은 .NET, C#, Java, Python, 또는 Node.js를 다루는 개발자를 위한 콘텐츠를 만드나요? 당신의 전문성을 추가 수입으로 전환하세요!

아이언 서포트 팀

저희는 주 5일, 24시간 온라인으로 운영합니다.
채팅
이메일
전화해