在我的Android应用中,我有一个多步登录过程:
firstCall(id)
secondCall(password)
有1个wrongId()
和correctId()
回调。
有用于2的wrongPassword()
和correctPassword()
回调。
我已经通过使用MVP模式在Android应用程序中成功实现了这一目标。
由于我在不同的活动(全部在MVP中)上使用了此登录过程,因此我有很多重复的代码。我将此登录信息提取到了一个separat类中,该类仍将在演示者中使用。但是,我有要求输入错误密码的问题吗?
我需要在所有演示者中实现的回调吗? 如何将错误的密码等通知当前使用的演示者?
答案 0 :(得分:0)
您可以通过多种方法来执行此操作,但是实施会受到多种因素的影响。有关您的案例的更具体的示例,您需要提供有关系统及其要求的更多信息。另外一些示例代码也会有所帮助。
执行此操作的一种方法是对所有支持登录的演示者使用基类。这是一个简化的示例(为简单起见,我将跳过无效输入的检查和重试,还必须提供更多详细信息和示例代码,以便给出适合您情况的更详细示例):< / p>
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 界面的视图,该界面可以重用或用作基类。