정적 설계와 인스턴스 설계
정적 상태가 적절한 경우를 판단합니다.
정적 설계와 인스턴스 설계은(는) CoddyKit의 무료 C# Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C# Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
설계 결정
static과 instance 중 무엇을 선택할지는 설계 선택입니다. 핵심 질문은 동작이 객체별 상태에 따라 달라지는지, 아니면 입력에만 의존하는지입니다.
using System;
class Program
{
// Depends only on inputs -> good static method
static int Max(int a, int b) => a > b ? a : b;
static void Main()
{
Console.WriteLine(Max(3, 8));
}
}상태가 없는 로직에는 정적 멤버 사용하기
메서드에 인스턴스 필드가 필요 없고 입력만 변환한다면 static으로 만드세요. 수학 도우미와 형식 지정자가 대표적인 예입니다.
using System;
static class Convert2
{
public static double MilesToKm(double miles) => miles * 1.60934;
}
class Program
{
static void Main()
{
Console.WriteLine(Convert2.MilesToKm(10).ToString("0.0") + " km");
}
}상태에는 인스턴스 사용하기
동작이 객체마다 달라지는 데이터에 의존한다면 instance를 사용하세요. 각 객체가 자체 상태를 가집니다.
using System;
class Counter
{
private int _count;
public void Increment() => _count++;
public int Value => _count;
}
class Program
{
static void Main()
{
var a = new Counter();
var b = new Counter();
a.Increment();
a.Increment();
b.Increment();
Console.WriteLine("a=" + a.Value + ", b=" + b.Value);
}
}공유 상태는 전역 상태입니다
정적 필드는 사실상 전역입니다. 프로그램의 여러 부분에서 읽고 쓰면 미묘한 버그가 발생할 수 있습니다. 사용자마다 자신의 복사본이 필요하다면 인스턴스 상태를 우선하세요.
using System;
class BadCart
{
public static int Items; // shared by EVERYONE -> usually wrong for a cart
}
class Program
{
static void Main()
{
BadCart.Items++;
BadCart.Items++;
Console.WriteLine("All carts share: " + BadCart.Items);
}
}테스트 가능성
순수 정적 메서드는 테스트하기 쉽습니다. 입력이 같으면 출력도 같기 때문입니다. 하지만 변경 가능한 정적 상태는 테스트 간에 새어 나가 테스트를 취약하게 만듭니다.
using System;
static class Calc
{
public static int Add(int a, int b) => a + b; // trivially testable
}
class Program
{
static void Main()
{
Console.WriteLine(Calc.Add(2, 2) == 4 ? "pass" : "fail");
}
}팩토리 도우미에는 정적 멤버 사용하기
정적 팩토리 메서드는 설명적인 이름으로 설정된 인스턴스를 만드는 깔끔한 방법입니다.
using System;
class Color
{
public int R, G, B;
private Color(int r, int g, int b) { R = r; G = g; B = b; }
public static Color Red() => new Color(255, 0, 0);
public static Color White() => new Color(255, 255, 255);
}
class Program
{
static void Main()
{
var c = Color.Red();
Console.WriteLine(c.R + "," + c.G + "," + c.B);
}
}new를 생략하려고 정적 멤버를 사용하지 마세요
객체를 만드는 일을 피하려고 모든 것을 정적으로 만들지 마세요. 형식이 상태를 가진 대상을 모델링한다면 인스턴스를 사용해야 그 상태를 서로 격리하고 안전하게 유지할 수 있습니다.
using System;
class Player
{
public string Name;
public int Health = 100;
public void TakeDamage(int d) => Health -= d;
}
class Program
{
static void Main()
{
var p1 = new Player { Name = "A" };
var p2 = new Player { Name = "B" };
p1.TakeDamage(30);
Console.WriteLine(p1.Name + ": " + p1.Health + ", " + p2.Name + ": " + p2.Health);
}
}두 방식을 적절히 섞기
많은 클래스에서는 공유 상수나 카운터에 정적 멤버를 사용하고, 객체별 데이터에는 인스턴스 멤버를 사용합니다. 이러한 조합은 완전히 관용적인 방식입니다.
using System;
class Invoice
{
private static int _seq = 1000;
public readonly int Number;
public decimal Amount;
public Invoice(decimal amount)
{
Number = _seq++;
Amount = amount;
}
}
class Program
{
static void Main()
{
var i1 = new Invoice(50m);
var i2 = new Invoice(75m);
Console.WriteLine(i1.Number + " / " + i2.Number);
}
}동시성 관련 주의점
공유 정적 상태에는 여러 스레드가 동시에 접근할 수 있어 경쟁 조건이 발생할 위험이 있습니다. 한 스레드에 한정된 인스턴스 상태가 기본적으로 더 안전합니다.
using System;
class SafeCalc
{
// No shared mutable state -> naturally thread-safe
public static long Factorial(int n)
{
long result = 1;
for (int i = 2; i <= n; i++) result *= i;
return result;
}
}
class Program
{
static void Main()
{
Console.WriteLine(SafeCalc.Factorial(5));
}
}간단한 판단 기준
Static = 형식에 속하며 객체별 상태를 사용하지 않는 동작입니다. Instance = 특정 객체를 읽거나 변경하는 동작입니다. 확신이 없다면 상태가 필요한 항목에는 인스턴스를 우선하세요.
using System;
class Temperature
{
public double Celsius; // instance state
public static double ToF(double c) => c * 9 / 5 + 32; // stateless helper
}
class Program
{
static void Main()
{
var t = new Temperature { Celsius = 30 };
Console.WriteLine(Temperature.ToF(t.Celsius));
}
}함께 적용하기
좋은 설계는 상태가 없는 도우미(정적 멤버)와 상태가 있는 모델(인스턴스)을 분리하여, 공유되는 변경 가능 상태를 의도적으로 최소화합니다.
using System;
static class TaxRules
{
public static decimal Apply(decimal amount, decimal rate) => amount + amount * rate;
}
class Sale
{
public decimal Subtotal;
public decimal Total(decimal rate) => TaxRules.Apply(Subtotal, rate);
}
class Program
{
static void Main()
{
var s = new Sale { Subtotal = 100m };
Console.WriteLine(s.Total(0.2m));
}
}빠른 확인
static과 instance 설계의 차이에 대한 이해도를 확인해 보세요.
복습
입력에만 의존하는 상태 없는 로직(도우미, 팩토리, 상수)에는 static을 선택하고, 객체별 상태와 연결된 동작에는 instance를 선택하세요. 변경 가능한 정적 상태는 사실상 전역이므로 테스트하기 어렵고 동시성 버그가 발생할 위험도 있습니다. 따라서 이를 최소화하고 의도적으로 사용하세요.
using System;
static class Util { public static int Sq(int n) => n * n; }
class Box { public int Size; public int Area() => Util.Sq(Size); }
class Program
{
static void Main()
{
var box = new Box { Size = 4 };
Console.WriteLine(box.Area());
}
}자주 묻는 질문
“정적 설계와 인스턴스 설계” 강의는 무료인가요?
네 — “정적 설계와 인스턴스 설계” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C# Academy 강의 전체를 잠금 해제할 수 있습니다. C# Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“정적 설계와 인스턴스 설계”에서 뭘 배우나요?
정적 상태가 적절한 경우를 판단합니다. 브라우저에서 직접 실행하는 실습 코드로 C# Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
C# Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 C# Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“정적 설계와 인스턴스 설계” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 C# Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 C# Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 정적 메서드와 필드
- 유틸리티용 정적 클래스
- 상수 및 readonly 필드
- 정적 설계와 인스턴스 설계