透过android案例熟知状态模式(二)

前面一篇博客是用简单java例子来熟悉状态设计模式,而这篇我将以android登录的例子继续讲解状态设计模式。
一.android中状态设计模式应用场景
在android开发中,我们遇到登录界面是十分常见的,而状态设计模式在登录界面的应用十分广泛,用户在登录状态下和未登录状态下,对逻辑的操作是不一样的。例如最常见的情况就是在玩新浪微博的时候,用户在登录的情况下才能完成评论和转发微博的操作;而当用户处于未登录的情况下要执行转发和评论微博的操作需要进入登录界面登录以后才能执行,所以面对这两者不同的状况,利用状态设计模式来设计这个例子最好不过。

二.设计流程
下面我们利用状态设计模式来简单的实现这个过程首先我们创建一个android项目,此项目的里面有两个Activity,分别是LoginActivity和MainActivity,其中入口Activity是LoginActivity,当用户登录成功就进入MainActivity,里面包含转发,评论,注销等操作。下面是整个项目的截图:
透过android案例熟知状态模式(二)_第1张图片

由于最近在学习javaweb,正好想到可以结合状态模式做一个登录的操作,这里顺便贴一下javaweb端的代码吧,服务器用的是Tomcat 8; 数据库用的是mysql;下面是servlet端的代码。利用prepareStatement可以防止SQL注入,具体使用请百度一下,我这里不做多的讲解,大致流程:
1,android客户端通过post请求加上username和password这两个参数;
2,服务器端拿到这两个请求参数然后查询数据库,当查询数据库存在此用户,则利用response.getWriter()输出一个200的code;
下面附上我本地数据库的图片:
透过android案例熟知状态模式(二)_第2张图片

public class LoginServlet extends HttpServlet {

    private Connection conn;
    private PreparedStatement ps;
    private ResultSet rs;
    private PrintWriter writer;

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String name = request.getParameter("username");
        String pwd = request.getParameter("password");

        try {
            writer = response.getWriter();
            conn = DBUtils.getConnection();
            String sql = "select username,password from t_user where username=? and password=?";
            ps = conn.prepareStatement(sql);
            ps.setString(1, name);
            ps.setString(2, pwd);
            rs = ps.executeQuery();
            while(rs.next()){
                writer.write("200");
                writer.flush();
                break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(writer!=null){
                writer.close();
                writer = null;
            }
            //DBUtils.closeResources(conn, ps, rs);
        }
    }

三.android客服端的代码实现
1.状态基类
前面我们讲过状态设计模式的原理实则是多态,在这里我们用UserState接口表示此基类,包换转发操作和评论这两种状态,代码如下:

public interface UserState {

    /**
     * 转发操作
     * @param context
     */
    public void forword(Context context);
    /**
     * 评论操作
     * @param context
     */
    public void commit(Context context);
}

2.用户在登录和未登录两种状况下的实现类LoginState和LogoutState;代码如下:
在LoginState.java中,用户是可以执行转发和评论操作。

public class LoginState implements UserState{

    @Override
    public void forword(Context context) {
        Toast.makeText(context, "转发成功", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void commit(Context context) {
        Toast.makeText(context, "评论成功", Toast.LENGTH_SHORT).show();
    }   
}

在LogoutState.java中,用户在未登录的情况下不允许执行操作,而是应该跳转到登录界面执行登录以后才可以执行。

public class LogoutState implements UserState{

    /**
     * 跳转到登录界面登录以后才能转发
     */
    @Override
    public void forword(Context context) {
        gotoLohinActivity(context);
    }
    /**
     * 跳转到登录界面登录以后才能评论
     */
    @Override
    public void commit(Context context) {
        gotoLohinActivity(context);
    }
    /**
     * 界面跳转操作
     * @param context
     */
    private void gotoLohinActivity(Context context){
        context.startActivity(new Intent(context,LoginActivity.class));
    }
}

3.操作角色LoginContext
这里的LoginContext就是在状态模式的Context角色,是用户操作对象和管理对象,LoginContext委托相关的操作给状态对象,在其中状态的发生改变,LoginContext的行为也发生改变。LoginContext的代码如*下:
温馨提示:
这里我们用到单例就是为了全局只有一个LoginContext去控制用户状态;

public class LoginContext {
    //用户状态默认为未登录状态
    UserState state = new LogoutState();
    private LoginContext(){};//私有构造函数,避免外界可以通过new 获取对象
    //单例模式
    public static LoginContext getInstance(){
      return SingletonHolder.instance;
    }
    /**
    *静态代码块
    */
    private static class SingletonHolder{
      private static final LoginContext instance = new LoginContext();
    }

    public void setState(UserState state){
        this.state = state;
    }
    //转发
    public void forward(Context context){
        state.forword(context);
    }
    //评论
    public void commit(Context context){
        state.commit(context);
    }
}

4,界面展示
LoginActivity.java,此界面执行登录操作,登录成后把 LoginContext.getInstance().setState(new LoginState());设置为登录状态,在MainActivity中就执行的是登录状态下的操作,即可以转发可评论;

public class LoginActivity extends Activity implements OnClickListener{

    private static final String LOGIN_URL = "http://10.10.200.193:8080/Day01/servlet/LoginServlet";
    private EditText et_username;
    private EditText et_password;
    private Button btn_login;

    private String username;
    private String password;
    private KJHttp http;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        initView();
        initData();
    }


    private void initView() {
        et_username = (EditText) findViewById(R.id.et_username);
        et_password = (EditText) findViewById(R.id.et_password);
        btn_login = (Button) findViewById(R.id.btn_login);
        btn_login.setOnClickListener(LoginActivity.this);
    }

    private void initData() {
        http = new KJHttp();
    }

    /**
     * 执行登录操作
     * 
     * @param username2
     * @param password2
     */
    protected void sendLogin(String username2, String password2) {
        HttpParams params = new HttpParams();
        params.put("username", "user1");
        params.put("password", "123456");
        http.post(LOGIN_URL, params, new HttpCallBack() {

            @Override
            public void onSuccess(String t) {
                if ("200".equals(t)) {
                    //设置为登录状态
                    LoginContext.getInstance().setState(new LoginState());
                    startActivity(new Intent(LoginActivity.this,MainActivity.class));
                    finish();
                    Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_login:
            username = et_username.getEditableText().toString().trim();
            password = et_password.getEditableText().toString().trim();
            if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
                Toast.makeText(LoginActivity.this, "用户名密码不能为空", Toast.LENGTH_SHORT).show();
                return;
            }
            sendLogin(username, password);
            break;
        }
    }

}

MainActivity.java,在用户登录成功后,点击转发和评论执行的是登录状态下的操作,而当用户注销时,我们把LoginContext的状态设置为未登录状态;LoginContext.getInstance().setState(new LogoutState());此时在点击转发和评论操作时就会跳到用户登录界面。

public class MainActivity extends Activity {

    private Button btn_forward;
    private Button btn_commit;
    private Button btn_logout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initListener();
    }

    private void initView() {
        btn_forward = (Button) findViewById(R.id.btn_forward);
        btn_commit = (Button) findViewById(R.id.btn_commit);
        btn_logout = (Button) findViewById(R.id.btn_logout);
    }

    private void initListener() {
        //转发操作
        btn_forward.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //调用LoginContext里面的转发函数
                LoginContext.getInstance().forward(MainActivity.this);
            }
        });
        //评论操作
        btn_commit.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //调用LoginContext里面的转发函数
                LoginContext.getInstance().commit(MainActivity.this);
            }
        });

        //注销操作
        btn_logout.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //设置为注销状态
                LoginContext.getInstance().setState(new LogoutState());
            }
        });
    }
}

6.图片展示
透过android案例熟知状态模式(二)_第3张图片
透过android案例熟知状态模式(二)_第4张图片
到此状态模式分析完毕。。。。。。

逆风的方向,更适合飞翔。

你可能感兴趣的:(设计模式)