Flutter에서 SOLID 원칙을 따르는 코드 작성법
Flutter로 고품질의 유지보수 가능한 소프트웨어를 개발하기 위해서는 SOLID 원칙을 따르는 것이 중요합니다. SOLID 원칙은 객체 지향 프로그래밍(OOP)의 핵심 가이드라인으로, 코드의 유연성과 재사용성을 극대화하고 버그를 줄이며 팀 간 협업을 개선할 수 있는 구조를 제공합니다. 이 글에서는 각 SOLID 원칙이 무엇인지 설명하고, 이를 Flutter 애플리케이션에서 적용하는 방법을 예제와 함께 알아보겠습니다.
1. Single Responsibility Principle (SRP) - 단일 책임 원칙
정의: 클래스나 함수는 오직 하나의 책임만 가져야 합니다. 즉, 변경 사유가 하나뿐이어야 합니다.
Flutter 예제 적용:
잘못된 예시: UI 로직과 데이터 처리 로직이 혼재된 클래스
class UserProfilePage extends StatelessWidget {
final ApiService apiService;
UserProfilePage({required this.apiService});
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: apiService.getUserData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
return Text('User: ${snapshot.data?.name}');
},
);
}
}
개선된 예시: 데이터 처리를 분리한 코드
class UserProfilePage extends StatelessWidget {
final UserViewModel viewModel;
UserProfilePage({required this.viewModel});
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: viewModel.fetchUserData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
return Text('User: ${snapshot.data?.name}');
},
);
}
}
class UserViewModel {
final ApiService apiService;
UserViewModel(this.apiService);
Future<User> fetchUserData() => apiService.getUserData();
}
이점: UI와 비즈니스 로직이 분리되어 테스트 및 유지보수가 용이합니다.
2. Open/Closed Principle (OCP) - 개방/폐쇄 원칙
정의: 클래스는 확장에는 열려 있어야 하지만, 수정에는 닫혀 있어야 합니다.
Flutter 예제 적용:
잘못된 예시: 기능 확장을 위해 기존 코드를 수정해야 하는 경우
class PaymentService {
void payWithCreditCard() {
print("Paid with Credit Card");
}
void payWithPaypal() {
print("Paid with PayPal");
}
}
개선된 예시: 인터페이스를 통한 확장 가능 구조
abstract class PaymentMethod {
void pay();
}
class CreditCardPayment implements PaymentMethod {
@override
void pay() {
print("Paid with Credit Card");
}
}
class PaypalPayment implements PaymentMethod {
@override
void pay() {
print("Paid with PayPal");
}
}
class PaymentService {
void processPayment(PaymentMethod paymentMethod) {
paymentMethod.pay();
}
}
이점: 새로운 결제 수단 추가 시 기존 코드를 수정할 필요 없이 확장이 가능합니다.
3. Liskov Substitution Principle (LSP) - 리스코프 치환 원칙
정의: 서브 클래스는 언제나 부모 클래스를 대체할 수 있어야 합니다.
Flutter 예제 적용:
잘못된 예시: 서브 클래스가 부모 클래스의 동작을 깨트리는 경우
class Rectangle {
double width;
double height;
Rectangle(this.width, this.height);
double get area => width * height;
}
class Square extends Rectangle {
Square(double side) : super(side, side);
}
개선된 예시: 상속 대신 조합(Composition) 사용
class Shape {
double get area => 0;
}
class Rectangle extends Shape {
double width;
double height;
Rectangle(this.width, this.height);
@override
double get area => width * height;
}
class Square extends Shape {
double side;
Square(this.side);
@override
double get area => side * side;
}
이점: 서브 클래스가 부모 클래스의 동작 규칙을 어기지 않고 동작합니다.
4. Interface Segregation Principle (ISP) - 인터페이스 분리 원칙
정의: 클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 합니다.
Flutter 예제 적용:
잘못된 예시: 모든 기능을 가진 거대한 인터페이스
abstract class NotificationService {
void sendEmail();
void sendSMS();
void sendPushNotification();
}
개선된 예시: 작은 인터페이스로 분리
abstract class EmailNotification {
void sendEmail();
}
abstract class SMSNotification {
void sendSMS();
}
abstract class PushNotification {
void sendPushNotification();
}
이점: 클라이언트는 필요한 인터페이스에만 의존하게 되어 더 유연하고 유지보수하기 쉬워집니다.
5. Dependency Inversion Principle (DIP) - 의존성 역전 원칙
정의: 고수준 모듈은 저수준 모듈에 의존해서는 안 되며, 둘 다 추상화에 의존해야 합니다.
Flutter 예제 적용:
잘못된 예시: 구체적인 클래스에 직접 의존
class UserService {
final ApiService apiService = ApiService();
void fetchData() {
apiService.getData();
}
}
개선된 예시: 의존성 주입 사용
class UserService {
final ApiService apiService;
UserService(this.apiService);
void fetchData() {
apiService.getData();
}
}
class ApiService {
void getData() {
print("Fetching data");
}
}
이점: 클래스가 특정 구현체에 종속되지 않으므로 테스트가 용이합니다.
결론
SOLID 원칙을 지키면 Flutter 프로젝트에서 유지보수성과 확장성을 높일 수 있습니다.
'Flutter' 카테고리의 다른 글
Flutter에서 앱 스위처(App Switcher) 미리보기 화면 제어하기 (0) | 2025.02.19 |
---|---|
Flutter에서 앱 아이콘 변경하기 (0) | 2025.02.19 |
Flutter에서 Native 코드와 통신하기 (0) | 2025.02.01 |
Flutter WebRTC: 실시간 통신 앱 개발 가이드 (0) | 2025.01.31 |
Flutter에서의 프로파일링(Profiling) 기법 및 성능 최적화 방법 (0) | 2025.01.31 |