有几种方法可以做到这一点,但实施会受到几个因素的影响。有关您的案例的更具体示例,您需要提供有关系统及其要求的更多信息。一些示例代码也会有所帮助。
- 如果您需要从多个地方登录,每个地方的视图是否不同?
- 登录过程有什么不同,所有登录都是一样的还是不同的?
您可以做到这一点的一种方法是为所有支持登录的演示者使用基类。这是一个简化的示例(为简单起见,我将跳过检查和重试无效输入,您还必须提供更多详细信息和示例代码,以便给出适合您情况的更详细示例):
public interface Api {
bool isIdValid(UUID id);
Token getToken(UUID id, string password);
}
public interface LoginView {
UUID askUserForId();
string askUserForPassword();
void notifyForInvalidId();
void notifyForInvalidPassword();
void showNoMorePasswordAttemptsAllowed();
}
public class LoginPresenterBase {
private Api mApi;
private LoginView mLoginView;
public LoginPresenterBase(LoginView loginView, Api api, other stuff){
mApi = api;
mLoginView = loginView;
}
public Token doLogin() {
UUID id = null;
while(true) {
id = mLoginView.askUserForId();
// add end condition here so you don't cycle forever when the user clicks
a cancel button or whatever
if(!mApi.isIdValid(id)) {
mLoginView.notifyForInvalidId();
}
else {
break;
}
}
for(int i = 0; i < retriesCount; ++i) {
stirng password = mLoginView.askUserForPassword();
// exit if the user clicks a cancel button or closes the dialog.
Token token = null;
try {
token = mApi.getToken(id, password);
}
catch(InvalidPasswordException) {
if(i == retriesCount - 1){
// if last retry
mLoginView.showNoMorePasswordAttemptsAllowed();
}
else {
mLoginView.notifyForInvalidPassword();
}
}
return token;
}
}
}
另一种方法是创建一个登录过程来表示步骤的顺序。由于此过程需要从外部(例如用户在 UI 窗口中输入)提供一些数据(例如密码),您可以使用交互或回调从您的 登录过程 em> 有人向它提供所需的数据。
通过这种方式,您可以插入不同的视图和/或演示者以添加特定的逻辑(例如密码输入)并重用流程。
这是一个例子:
public interace IdProvider {
public UUID getId();
public void invalidIdProvided(UUID);
}
public interface PasswordProvider {
public string getPassword();
public void invalidPasswordProvided(string password);
public void maxPasswordAttemptsReached();
}
public class LoginProcess {
private Api mApi;
private IdProvider mIdProvider;
private PasswordProvider mPasswordProvider;
public LoginProcess(
IdProvider idProvider, PasswordProvider passwordProvider, Api api) {
mApi = api;
mIdProvider = idProvider;
mPasswordProvider = passwordProvider;
}
public Token execute() {
UUID id = null;
while(true) {
id = mIdProvider.getId();
if(!mApi.isIdValid(id)) {
mIdProvider.invalidIdProvided(id);
// add end condition here so you don't cycle forever when the
// user clicks a cancel button or whatever
}
else {
break;
}
}
for(int i = 0; i < retriesCount; ++i) {
string password = mPasswordProvider.getPassword();
Token token = null;
try {
token = mApi.getToken(id, password);
}
catch(InvalidPasswordException) {
if(i == retriesCount - 1){
// if last retry
mPasswordProvider.maxPasswordAttemptsReached();
}
else {
mPasswordProvider.invalidPasswordProvided();
}
}
return token;
}
}
通过这种方式,您可以插入不需要的每个视图/演示器。只需实现接口,该过程将在一个单独的对象中。如有必要,您可以创建一个实现接口的基本演示者。
LoginProcess 类的最后一个解决方案具有最好的Separation of Concerns 并使用Single Responsibility Principle。
问题在于您必须定义另一组接口和类。
第一个使用较少的代码并且仍然有效。您可以重用演示者,并且可以创建实现 LoginView 接口的视图,您可以重用或用作基类。