状态模式&策略模式

来源:互联网 发布:淘宝联盟旧版本5.2 编辑:程序博客网 时间:2024/06/04 19:50

状态模式,这个模式在android中的运用特别,比如同一个按钮,需要根据点击事件的不同执行不同的业务逻辑,比如新浪微博,他里面有匿名登陆和实名登陆

匿名登陆环境:点击底部导航我的按钮,会显示一个提醒登陆的页面
如果是账号登陆环境,之间显示的我的个人信息,也就是说不同状态下点击事件展示的不一样的画面,这个时候我们怎么办,通过if else处理? 坚决不是,太low了,当然也不能说low,这个需要具体环境来定,下面就是一个额用状态模式的例子,感受一下


模拟状态:用户匿名登录和实名登录显示不同内容信息,登录程序首页显示有两个按钮功能,分别是转发和评论,如果是未登录状态跳转到登录页面,已登录直接更新UI

  1. 通过接口设置页面功能
/** * 登录页面功能接口 *  * @author user *  */public interface UserState {    /**     * 转发     * @param context     */    public void forward(Context context);    /**     * 评论     * @param context     */    public void comment(Context context);}

1)已登录状态

/** * 已登录状态,执行具体的功能操作 *  * @author user *  */public class LoginedState implements UserState {    @Override    public void forward(Context context) {        // TODO Auto-generated method stub        Toast.makeText(context, "转发微博", Toast.LENGTH_SHORT).show();    }    @Override    public void comment(Context context) {        // TODO Auto-generated method stub        Toast.makeText(context, "评论微博", Toast.LENGTH_SHORT).show();    }}

2)未登录状态

/** * 未登录状态,跳转到登录页面 *  * @author user *  */public class LoginState implements UserState {    @Override    public void forward(Context context) {        // TODO Auto-generated method stub        gotoLoginActivity(context);    }    @Override    public void comment(Context context) {        // TODO Auto-generated method stub        gotoLoginActivity(context);    }    private void gotoLoginActivity(Context context) {        Intent intent = new Intent(context, LoginActivity.class);        context.startActivity(intent);    }}
  1. 设置用户接口和状态管理类(默认设置为未登录状态)
public class LoginContext {    UserState state = new LoginState();// 默认未登录状态    // 私有构造器,设置单例模式    private LoginContext() {    }    /**     * 设置静态内部类单例模式     *      * @return     */    public static LoginContext getInstace() {        return LoginHolder.sinstance;    }    public static class LoginHolder {        private static final LoginContext sinstance = new LoginContext();    }   //设置登录状态到构造器    public void setState(UserState state) {        this.state = state;    }    // 测试转发和评论功能    public void forward(Context context) {        state.forward(context);    }    public void comment(Context context) {        state.comment(context);    }}
  • 首页核心代码如下:
......  @Override    public void onClick(View v) {        // TODO Auto-generated method stub        switch (v.getId()) {        case R.id.tv_forward://            LoginContext.getInstace().forward(this);// 转发            break;        case R.id.tv_login://            LoginContext.getInstace().comment(this);// 评论        default:            break;        }    }
  • 登录页面核心代码
    @Override    public void onClick(View v) {        // TODO Auto-generated method stub        switch (v.getId()) {        case R.id.button:            LoginContext.getInstace().setState(new LoginedState());// 登录成功            finish();            break;        default:            break;        }    }...
  • 结果说明:默认情况下状态管理类里面设置为未登录状态,即匿名登录,此时state实例对象为初始化德未登录状态,点击转发或者评论按钮跳转至登录页面,在登录页面里面我们可以设置state对象为登录状态,此时再次点击转发按钮会执行转发操作

对于状态模式和策略模式理解总是很模糊,最近写了几个Demo稍微有点理解了,下面说一下我的理解

  • 状态模式:顾名思义,状态模式的重点就是状态二字,比如我们例子中的两种状态,登录状态和未登录状态,登录状态下可以执行具体的事件,未登录状态跳转至登录页面,两种不同的状态
  • 而策略模式是状态模式的一个分支下的扩展,重点是策略二字,如果这儿,登录状态下可以购买打折商品,比如运动服8折,上衣9折这种情况下我们做了一个动作,那就是买衣服,但是买的衣服确是不同的折扣,也就是执行不同的策略

  • 第一步,先定义对象,对象中定义三个变量,tyle【衣服种类】、Name【衣服名称】、Price【价格】

public class goods {    String Type;    String Name;    double Price;    public goods(String type, String name, double price) {        Type = type;        Name = name;        Price = price;    }    @Override    public String toString() {        return "goods{" +                "Type='" + Type + '\'' +                ", Name='" + Name + '\'' +                ", Price=" + Price +                '}';    }    public double getPrice() {        return Price;    }    public void setPrice(double price) {        Price = price;    }    public String getType() {        return Type;    }    public String getName() {        return Name;    }    public void setType(String type) {        Type = type;    }    public void setName(String name) {        Name = name;    }}
  • [x] 下面是具体的执行策略,首先定义接口
/** * Created by wangyawen on 2016/12/26 0026. * 定义一个打折策略接口 */public interface discountStrategyImpl {    double GetDiscount(goods goods);}
  • 定义具体的策略,这儿有运动鞋和衬衫,首先定义衬衫的具体打折策略
/** * 衬衫打折策略 * Created by wangyawen on 2016/12/26 0026. */public class Shirt implements discountStrategyImpl {    @Override    public double GetDiscount(goods goods) {        return 0.9 * goods.getPrice();    }}
  • 然后是运动鞋的打折策略
/** * Created by wangyawen on 2016/12/26 0026. * 运动鞋打折策略 */public class Sports implements discountStrategyImpl {    @Override    public double GetDiscount(goods goods) {        return 0.8 * goods.getPrice();    }}

对比一下发现和状态模式很混是吧,其实也好理解,当前是一种状态,也就是买衣服这一种状态,不在区分是否有钱,而是否有钱就是两种状态了,没钱去银行取钱,有钱就可以直接买衣服,而买衣服这一个状态有不同的策略而已

  • [x] 接下来拿起购物车开始购物吧,当然购物过程中存在添加和删除操作,还有计算金额,万一超过总金额那不就尴尬了
public class ShoppingCar {    private List<goods> goodsList = new ArrayList<>();    /**     * 添加商品到购物车     *     * @param goods     */    public void AddGoods(goods goods) {        goodsList.add(goods);    }    /**     * 移除商品     *     * @param goods     */    public void RemoveGoods(goods goods) {        goodsList.remove(goods);    }    /**     * 获取购物车中所有商品     *     * @return     */    public List<goods> getGoodsList() {        return goodsList;    }    /**     * 获取商品的基础价格【实际价格】     * @return     */    public double outPrice() {        double sum = 0;        for (int i = 0; i < goodsList.size(); i++) {            sum += goodsList.get(i).getPrice();        }        return sum;    }}
  • [x] 购物结束,下面该去柜台结算了,那就需要创建一个柜台的功能类了,请看下面代码
/** * 收银台 * Created by wangyawen on 2016/12/26 0026. */public class CashierDesk {    /*购物车*/    private ShoppingCar car;    /*数据字典,等会研究一下这玩意*/    private Map<String, discountStrategyImpl> strategies;    public CashierDesk(ShoppingCar car, Map<String, discountStrategyImpl> s) {        this.car = car;        this.strategies = s;    }    /**     * 商品总价     *     * @return     */    public double GetTotalPrice() {        return car.outPrice();    }    /**     * 商品实际价格     *     * @return     */    public double GetTotalDiscount() {        double sum = 0;        /*定义一个接口引用对象*/        discountStrategyImpl idiscountStrategy;        for (goods g : car.getGoodsList()) {            /*拿到具体的执行策略*/            idiscountStrategy = strategies.get(g.getType());            if (idiscountStrategy != null) {                sum += idiscountStrategy.GetDiscount(g);            }        }        return sum;    }}
  • 在上面代码中我们主要的功能就是算出商品总额以及打折之后的金额,其实柜台也就这两个功能,下面就该算账了,想想都肉疼
/** * Created by wangyawen on 2016/12/26 0026. */public class Client {    public static void main(String[] arg) {        ShoppingCar sc = new ShoppingCar();        /**这个也就是我们刚才说要研究的数据字典,其实也没啥,就是通过map对象配置打折策略,看到后面就明白了*/        Map<String, discountStrategyImpl> map = new HashMap<>();        //向购物车中加入商品        sc.AddGoods(new goods("shirt", "cap", 100));        sc.AddGoods(new goods("shirt", "sleeve", 200));        sc.AddGoods(new goods("sports", "sp_cap", 150));        sc.AddGoods(new goods("sports", "sp_pants", 150));        //配置折扣策略        map.put("shirt", new Shirt());        map.put("sports", new Sports());        CashierDesk cd = new CashierDesk(sc, map);        //得到所有商品总价        System.out.println(cd.GetTotalPrice());        //得到所有商品折扣价        System.out.println(cd.GetTotalDiscount());    }}
0 0
原创粉丝点击