안녕하세요! 이 문서에는 개발 수행 방법에 관한 정책, 절차 및 표준에 대한 개인 권장 사항이 포함되어 있습니다.
프로젝트 코드는 폴더 별 폴더 와 폴더 별 유형별 로 구성되어야합니다.
루트 레벨에서는 기능을 정의하는 폴더가 있습니다. 예를 들어:
|-- common/
|-- authentication/
|-- settings/
Common/Core 기능에는 기본적으로 모든 기능에서 사용할 수있는 클래스, 기능 또는 위젯이 포함되어 있습니다.
따라서 아이디어는 응용 프로그램의 기능을 최상위 폴더로 나눈 값을 갖는 것입니다.
모든 최상위 폴더를 별도의 다트/플러터 패키지, 종속성 또는 응용 프로그램의 액세스 경계로 생각하십시오.
따라서 공통 폴더에 무언가를 추가하면 스스로에게 물어봐야합니다. 99.%의 기능이 필요합니까?
당신이 그것을 의존성으로 생각한다면, 공통 의존성은 항상 pubspec.yaml에 선언됩니다.
따라서 공통 폴더에 클래스, 기능 또는 위젯을 추가하기 전에 다음과 같이 물어보십시오.
각 기능 폴더 내부에는 폴더가 유형별로 정의되어 있습니다.
기능 폴더의 일부인 폴더 유형은 다음과 같습니다.
|-- ui/
|-- cubits/
|-- domain_objects/
|-- exceptions/
|-- use_cases
|-- services/
|-- repositories/
|-- data_sources/
|-- dtos/
단일 파일과 관련된 파일이 둘 이상인 경우 파일에서 클래스에 대한 클래스에 대한 코드를 생성하는 등 폴더로 파일을 그룹화 할 수 있습니다. 예를 들어:
|-- authentication/
|---- cubits/
|------ login/
|-------- login_cubit.dart
|-------- login_cubit.freezed.dart
|-------- login_cubit.g.dart
UI PageBuilders, UI 화면, UI보기, UI 구성 요소와 같은 사용자의 장치 인터페이스와 관련된 코드.
화면은 전체 장치 디스플레이를 채우는 사용자 인터페이스 구성 요소이며 사용자 인터페이스보기 또는 구성 요소 (버튼, 확인란, 이미지 및 ECT)의 컨테이너입니다.
또한 화면은 특정 응용 프로그램 내비게이션 대상입니다.
지침:
class LoginScreen extends StatelessWidget {
//...fields and constructor...
@override
Widget build ( BuildContext context) {
return Column (
children : < Widget > [
_LoginLogo ,
_LoginForm ,
_LoginActions ,
_LoginFooter
],
);
}
}
// extracted by use case.
class _LoginLogo extends StatelessWidget {}
// extracted by update area.
class _LoginForm extends StatefullWidget {}
// extracted by update area.
class _LoginActions extends StatelesssWidget {}
// extracted by update area.
class _LoginFooter extends StatelessWidget {} login_screen.dart
part 'login_screen_components.dart' ;
class LoginScreen extends StatelessWidget {
//...fields and constructor...
@override
Widget build ( BuildContext context) {
return Column (
children : < Widget > [
_LoginLogo ,
_LoginForm ,
_LoginActions ,
_LoginFooter
],
);
}
}
// Is kept here because it's does not break the 400 max line rule.
class _LoginLogo extends StatelessWidget {} login_screen_components.dart
part of 'login_screen.dart' ;
/// [LoginScreen] 's fields.
class _LoginForm extends StatelessWidget {}
// ************************ Footer ************************
/// [LoginScreen] 's footer.
class _LoginFooter extends StatelessWidget {}
// ************************* ACTIONS *********************************
/// [LoginScreen] 's actions.
class _LoginActions extends StatelessWidget {} class LoginScreen extends StatelessWidget {
@override
Widget build ( BuildContext context) {
return BlocBuilder < LoginCubit , LoginCubitState >(
// Here cubit is not specified either.
builder : ( BuildContext context, LoginCubitState state) {},
);
}
} class SomeWidget extends StatelessWidget {
@override
Widget build ( BuildContext context) {
//...
}
}
class _SubTree1 extends StatelessWidget {}
class _SubTree2 extends StatelessWidget {}
class _SubTree3 extends StatelessWidget {}
class _SubTree4 extends StatelessWidget {} class LoginScreen extends StatelessWidget {
@override
Widget build ( BuildContext context) {
return Column (
childreen : < Widget > [
Button1 (onClick : _openRegisterUser),
Button2 (onClick : _openLogin),
Field (onTextChanged : _onUserNameTextChanged),
],
);
}
void _openRegisterUser () {}
void _openLogin () {}
void _onUserNameTextChanged ( String newText) {}
}보기는 전체 장치 디스플레이를 채우지 않고 사용자 인터페이스보기 또는 구성 요소 (버튼, 확인란, 이미지 및 ECT)의 컨테이너 인 사용자 인터페이스 구성 요소입니다.
또한보기는 응용 프로그램 내비게이션 대상이 아닙니다.
지침:
Cubits는 UI에 대한 비즈니스 논리를 포함하는 클래스이며, Cubit은 UI 상태를 나타내는 상태에 묶여 있습니다.
가이드 라인 권장 사항 :
Future < String ?> bookAppointment ( BookingData booking);
Future < bool > login ( String username, String password);Cubit State Class는 주어진 시간에 UI 상태를 나타냅니다.
가이드 라인 권장 사항 :
class LoginState {
bool logginSuceeded // avoid this.
}도메인에서 단일 비즈니스 운영/목표/작업/작업을 만드는 데 사용되는 클래스.
지침 :
class GetCurrentUserUseCase , class SignInUseCase ;UseCase 가 있어야합니다.call() 있어야하며, 여기서 반환 유형은 유스 케이스를 실행 한 결과입니다.Repositories , Services 또는 기타 high level coordinators 에만 액세스해야합니다.DataSource 또는 Cubit 에 액세스하거나 DTO 또는 다른 낮은 레벨 객체와 상호 작용해서는 안됩니다 .Cubit 또는 다른 UseCases 에서 사용해야합니다.예 :
class GetCurrentUserUseCase {
final UserRepository _repository;
const GetCurrentUserUseCase ( this ._repository);
Future < User ?> call () async {
await _repository. getCurrentUser ();
}
} class AuthenticateMemberUseCase {
/// Create a [AuthenticateMemberUseCase] .
const AuthenticateMemberUseCase (
/* constructor arguments */
);
/* ... fields ...*/
/// Execute the use case.
Future < TegTask < void >> call ( MemberAuthenticationCredentials credentials) {
return runTaskSafelyAsync < void >(() async {
final bool isEmailValid = credentials.email.isEmail;
if ( ! isEmailValid) {
throw const TegEmailInvalidException ();
}
final bool isConnected = await _hostDeviceInternetService. isConnected ();
if ( ! isConnected) {
throw const TegInternetUnavailableException ();
}
final String ? deviceId = await _hostDeviceInfoRepository. getDeviceId ();
if (deviceId == null ) {
throw const TegDeviceIdUnavailableException ();
}
final PublicPrivateKeyPair keyPair = await _keyGenerator. generate ();
final Member member = await _authService. signIn (
email : credentials.email,
password : credentials.password,
deviceId : deviceId,
publicKey : keyPair.publicKey,
);
await _updateCurrentMemberUseCase (
member : member,
memberPrivateKey : keyPair.privateKey,
deviceId : deviceId,
);
await _saveMemberAuthenticationCredentialsUseCase (credentials);
final TegTask < List < Account >> memberAccountsTask = await _getMemberAccountsUseCase ();
if (memberAccountsTask.failed) {
throw memberAccountsTask.exception;
}
await _updateMemberCurrentAccountUseCase (
member : member,
deviceId : deviceId,
memberPrivateKey : keyPair.privateKey,
account : memberAccountsTask.result.first,
);
});
}
}예를 들어 특정 기능 또는 기능 범위에 대해 CRUD 작업 만 사용하여 데이터에 대한 액세스를 제공하는 클래스는 다음과 같습니다.
abstract class BookingRepository {
Futute < Booking > getBookingById ( String id);
Future < List < Booking >> getBookings ();
Future < void > deleteBookingById ( String id);
Future < void > saveBooking ( Booking booking);
}가이드 라인 권장 사항 :
class DefaultBookingRepository implements BookingRepository {
final LocalBookingDataSource local;
final RemoteBookingDataSource remote;
Future < Booking ?> getBookingById ( String id) async {
Booking ? savedBooking = await local. getBookingById (id);
if (savedBooking == null ) {
Booking ? remoteBooking = await remote. getBookingById (id);
if (remoteBooking != null ) {
await local. saveBooking (remoteBooking);
}
return remoteBooking;
}
return savedBooking;
}
//...other operations...
}인터페이스
abstract class BookingRepository {}구현
class DefaultBookingRepository implements BookingRepository {}
class AnonymousBookingRepository implements BookingRepository {}
class PremiumBookingRepository implements BookingRepository {}특정 기능 또는 기능 범위에 대한 기능에 대한 액세스를 제공하는 클래스는 다음과 같습니다.
abstract class AuthenticationService {
Future < void > authenticate ( String username, String password);
//...other functionalities...
}
abstract class AppointmentService {
Future < void > register ( Appointment appointment);
//...other functionalities...
}가이드 라인 권장 사항.
로컬 또는 원격으로 위치한 데이터에 대한 액세스를 구현하는 클래스. 예
abstract class LocalBookingDataSource {
Futture < void > saveBooking ( Booking booking);
//...other functionalities...
}
abstract class RemoteBookingDataSource {
Future <booking> saveBooking ();
}가이드 라인 권장 사항 :
class SQLiteBookingDataSource implements LocalBookingDataSource {
//...............Implementation................
}
class RestApiBookingDataSource implements RemoteBookingDataSource {
//...............Implementation................
}
class MemoryBookingDataSource implements LocalBookingDataSource {
//...............Implementation................
}데이터 전송 객체 - 한 시스템에서 다른 시스템으로 데이터를 전송하는 데 사용됩니다. 예
class ApiRequest {
//...fields...
}
class ApiResponse {
//...fields...
} class SQLiteTableDefinition {
//...fields...
}지침 :
class ApiRequest {
//...fields...
factory ApiRequest . fromDO ( DOObject doObject) {
//...mapper code...
}
DOObject toDO () {
//...mapper code...
}
}도메인 객체는 비즈니스의 일부 또는 해당 항목을 나타내는 데이터 클래스이며 플랫폼, 라이브러리 또는 도구와 독립적으로 비즈니스 로직을 실행하는 데 사용됩니다.
도메인 개체는 예를 들어 사람, 장소, 이벤트, 비즈니스 프로세스 또는 개념 및 송장, 제품, 거래 또는 사람의 세부 사항을 나타낼 수 있습니다.
지침:
프로젝트 코드 구조와 동일합니다.
먼저 기능 이름, 파일이 포함 된 assets 폴더.
예:
|-- authentication/
|---- assets/
|------ password_hidden_icon.svg
|------ forget_password_icon.svg
|------ background.png