策略模式定义
定义:就是定义一系列算法,把他们独立封装起来,并且这些算法之间可以相互替换。
说白了,策略模式能够大大的降低耦合度,当修改代码的时候不会牵一发而动全身。
适用范围
- 对某一功能在不同时期有不同算法要求,如购物打折
- 需要频繁改动,但是需要局域改动,如充话费活动
实例
现在模拟一个充话费的需求,假设现在又两种情况:
- 1.话费充50以下按实际金额收款
- 2.话费充值超过50,则按9.8折收款(这里的9.8折也不一定,所以这个参数也是不定的)
知道基本功能需求了,那么我们就要开始分析了,我们把这两种情况分为原价收款和打折收款,两种情况共性是都是收款,那好明确了这个需求我们就开始动手去撸代码;
- 首先定义好一个公共的策略接口,根据策略这个单词我们就叫他Strategy
/**
* Created by melo on 2017/2/9.
*策略抽象接口,定义所有收款算法
*/
public interface Strategy {
double acceptMoney(double money);
//当然如果分析需要别的功能可以继续写方法
}
- 做好第一步后,根据分析我们知道有两种收款的计算方法,那么我们就具体的把这两个收款的种类分别对应创建出来实现公共的策略接口Strategy
/**
* Created by melo on 2017/2/9.
* 原价收款
*/
public class OriginalPrice implements Strategy {
@Override
public double acceptMoney(double money) {
return money;
}
}
/**
* Created by melo on 2017/2/9.
* 打折收款,这其中可能不同活动的打折率是不一样的
*/
public class DiscountPrice implements Strategy {
//打折率
private double discountRate;
public DiscountPrice(double discountRate) {
this.discountRate = discountRate;
}
//根据打折率来计算最终的收款金额
@Override
public double acceptMoney(double money) {
return money * discountRate;
}
}
- 当我们把具体的收款种类写完之后,是否需要考虑怎么根据金额选择使用不同的收款方法,想过之后,你可能想到要一个控制strategy的对象
/**
* Created by melo on 2017/2/9.
* 定义一个接口,Strategy能够访问它
*/
public class StrategyContract {
private Strategy mStrategy;
private static StrategyContract instance;
private StrategyContract() {
}
public static StrategyContract getInstance() {
if (instance == null) {
instance = new StrategyContract();
}
return instance;
}
//根据金额判断需要实例化打折方式的对象
public void setStrategy(Type type, double... params) {
switch (type) {
case ORIGINAL:
mStrategy = new OriginalPrice();
break;
case DISCOUNT:
mStrategy = new DiscountPrice(params[0]);
break;
}
}
/**
* 得到最终的收款数
* @param money
* @return
*/
public double getFinalMoney(double money) {
return mStrategy.acceptMoney(money);
}
}
- 哦哦,还有一个枚举的收款类型,也很简单
/**
* Created by melo on 2017/2/9.
* 使用枚举
*/
public enum Type {
ORIGINAL, //原价
DISCOUNT; //打折
//...可以添加其他参数
Type() {
}
}
- 上边的几步也基本完成了对收款类型的功能代码,接下来就在as上测试一下
/**
* 策略模式
*/
public class MainActivity extends AppCompatActivity {
EditText startPrice, finalPrice;
Button mButton;
//实际收款
double finalMoney;
//充值金额
double startMoney;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startPrice = (EditText) findViewById(R.id.et_price_start);
finalPrice = (EditText) findViewById(R.id.et_price_final);
mButton = (Button) findViewById(R.id.btn_ok);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getFinalResult();
}
});
}
/**
* 获得最终结果
*/
private void getFinalResult() {
startMoney = Double.parseDouble(startPrice.getText().toString());
if (startMoney < 50.0) {
//原价
StrategyContract.getInstance().setStrategy(Type.ORIGINAL);
} else if (startMoney >= 50.0) {
//设置折扣
StrategyContract.getInstance().setStrategy(Type.DISCOUNT, 0.9);
}
finalMoney = StrategyContract.getInstance().getFinalMoney(startMoney);
finalPrice.setText(finalMoney + "");
}
}
**xml**
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="充值金额:"
android:textSize="18sp"/>
<EditText
android:id="@+id/et_price_start"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="元"
android:text="0"/>
</LinearLayout>
<Button
android:id="@+id/btn_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="确认"
android:textSize="18sp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="实收金额:"
android:textSize="18sp"/>
<EditText
android:id="@+id/et_price_final"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="元"/>
</LinearLayout>
</LinearLayout>
- 测试结果
策略模式的基本内容就这么多了,对于上述功能如果能结合工厂模式,那么可能判断的逻辑就可以完全可与客户端脱离,是极好的。可以自行去尝试。