你好!本文档包含我对应如何进行发展的政策,程序和标准的个人建议。
项目代码应与文件夹和逐型文件夹的混合结构结构。
含义在根级别,您的文件夹定义功能。例如:
|-- 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状态类代表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操作提供特定功能或功能范围的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