策略模式(Strategy)
策略模式是对象的行为模式。它的用意是针对一组算法,将每一个算法封装到具有共同接口的独立类中,从而使得它们可以相互替换。策略模式使得算法可以在不修改或影响到调用端的情况下发生变化。
下面来讨论下策略模式的结构类图,具体如下:
从上面的结构图中,我们可以看出策略模式涉及到了三个角色,具体角色如下所示:
A、抽象策略角色:这是个抽象角色,通常是由一个接口或是抽象类来实现。它为所有的具体策略类提供了需要的接口。
B、具体策略角色:这个角色包装了相关的算法和行为,用来执行对应的策略事件。
C、环境角色:这个角色中含有一个对抽象策略类的引用,也是供外部调用直接接触的角色。
下面具体举个例子来使用策略模式。例子是这样的:现在要做一个上网使用得app,接入的网络类型有三种,分别为CMCC、ChinaNet及普通的Wifi类型,所以针对这几种类型的网络,我们需要定义一个抽象的策略角色,然后再定义三个具体角色,每个具体的角色中实现具体的功能细节,最后,我们在前端放置三个按钮,点击对应的按钮调用对应的具体角色逻辑(通过调用抽象角色)。下面为我的代码逻辑实现以及部分说明文字:
抽象策略角色(WifiConnectStrategy):
/**
* 抽象策略角色
*/
public abstract class WifiConnectStrategy implements Callback{
private WifiConnectStrategyListener listener = null;
protected WifiState wifiState = null;
protected Handler handler = null;
protected static final long CONN_WIFI_TIME = 2000; // 连接wifi的时间(模拟)
public WifiConnectStrategy() {
handler = new Handler(WifiConnectStrategy.this);
}
public voidsetWifiConnectStrategyListener(WifiConnectStrategyListener listener) {
this.listener = listener;
}
/**
* 创建一个策略,根据wifitype
*/
public static WifiConnectStrategycreateWithWifiType(WifiType wifiType) {
WifiConnectStrategy result = null;
switch (wifiType) {
case CMCC:
result = new CMCCWifiConnectStrategy();
break;
case CHINANET:
result = new ChinaNetWifiConnectStrategy();
break;
case COMMON:
result = new CommonWifiConnectStrategy();
break;
default:
break;
}
return result;
}
public voidconfigWifiState(WifiState wifiState) {
this.wifiState = wifiState;
}
/**
* 连接到网络的方法
*/
public abstract void executeConnectNetRun();
/**
* 模拟链接后返回的结果
*/
public abstract void connectResult();
// 模拟网络链接延迟
protected void simulateConnect() {
this.handler.removeMessages(1);
this.handler.sendEmptyMessageDelayed(1,CONN_WIFI_TIME);
}
@Override
public booleanhandleMessage(Message msg) {
connectResult();
return true;
}
public WifiConnectStrategyListener getListener() {
return listener;
}
public voidsetListener(WifiConnectStrategyListener listener) {
this.listener = listener;
}
public void log(String log) {
Log.d("WifiConnectStrategy", log);
}
}
具体策略角色(CMCC):
/**
* 具体策略角色
*/
public class CMCCWifiConnectStrategy extends WifiConnectStrategy {
public CMCCWifiConnectStrategy() {
super();
}
@Override
public voidexecuteConnectNetRun() {
log("cmcc connect ...");
// 链接网络核心代码(异步)
// TODO
// 模拟网络链接延迟
simulateConnect();
}
@Override
public void connectResult(){
getListener().cmccConnResult(this.wifiState.getWifiLabel() +"连接成功!");
}
}
具体策略角色(ChinaNet):
public classChinaNetWifiConnectStrategy extendsWifiConnectStrategy {
public ChinaNetWifiConnectStrategy() {
super();
}
@Override
public voidexecuteConnectNetRun() {
log("chinanet connect ...");
// 链接网络核心代码
// TODO
// 模拟网络链接延迟
simulateConnect();
}
@Override
public void connectResult(){
getListener().cmccConnResult(this.wifiState.getWifiLabel() +"连接成功!");
}
}
具体策略角色(Common wifi):
public classCommonWifiConnectStrategy extendsWifiConnectStrategy {
public CommonWifiConnectStrategy() {
super();
}
@Override
public void executeConnectNetRun(){
log("common connect ...");
// 链接网络核心代码
// TODO
// 模拟网络链接延迟
simulateConnect();
}
@Override
public void connectResult(){
getListener().cmccConnResult(this.wifiState.getWifiLabel() +"连接成功!");
}
}
下面为我们具体的环境角色,主要就是引用一个抽象策略角色,以及根据不同网络类型创建对应的具体策略角色,具体如下:
public class MainActivity extends Activity implements OnClickListener {
private Button btnCmcc = null;
private Button btnChinanet = null;
private Button btnCommon = null;
private WifiConnectStrategy wifiConnectStrategy;
private WifiState selectedState = new WifiState();
private WifiConnectStrategyListener listener = new WifiConnectStrategyListener() {
@Override
public voidcmccConnResult(String state) {
log(state);
}
@Override
public void chinanetConnResult(Stringstate) {
log(state);
}
@Override
public voidcommonConnResult(String state) {
log(state);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnCmcc = (Button) findViewById(R.id.btnCmcc);
btnChinanet = (Button) findViewById(R.id.btnChinanet);
btnCommon = (Button) findViewById(R.id.btnCommon);
btnCmcc.setOnClickListener(this);
btnChinanet.setOnClickListener(this);
btnCommon.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (null != wifiConnectStrategy) {
wifiConnectStrategy = null;
}
if(v.getId() == R.id.btnCmcc) {
selectedState.setCardNo("cmcc+1167278922");
selectedState.setIpAddress(192168013);
selectedState.setPassword("123456");
selectedState.setWifiLabel("CMCC");
selectedState.setSsid("dafadfdadada");
selectedState.setWifiType(WifiType.CMCC);
wifiConnSpecial(selectedState);
}
else if (v.getId() == R.id.btnChinanet) {
selectedState.setCardNo("cmcc+1167272222");
selectedState.setIpAddress(192168433);
selectedState.setPassword("123456777");
selectedState.setWifiLabel("ChinaNet");
selectedState.setSsid("dafadeeeedada");
selectedState.setWifiType(WifiType.CHINANET);
wifiConnSpecial(selectedState);
}
else {
selectedState.setIpAddress(192168111);
selectedState.setPassword("123456789");
selectedState.setWifiLabel("COMMON");
selectedState.setSsid("dafadeeeSSDASF");
selectedState.setWifiType(WifiType.COMMON);
wifiConnCommon(selectedState);
}
}
private voidwifiConnSpecial(WifiState wifiState) {
wifiConnectStrategy = WifiConnectStrategy.createWithWifiType(selectedState.getWifiType());
wifiConnectStrategy.configWifiState(wifiState);
wifiConnectStrategy.setWifiConnectStrategyListener(listener);
wifiConnectStrategy.executeConnectNetRun();
}
private voidwifiConnCommon(WifiState wifiState) {
wifiConnectStrategy = WifiConnectStrategy.createWithWifiType(selectedState.getWifiType());
wifiConnectStrategy.configWifiState(wifiState);
wifiConnectStrategy.setWifiConnectStrategyListener(listener);
wifiConnectStrategy.executeConnectNetRun();
}
private void log(String log) {
Log.d("WifiConnectStrategy",log);
}
}
注意:这里的WifiState类为wifi的封装类,WifiConnectStrategyListener为监听网络链接的接口。接下来,我会在下面罗列出他们的代码构成。
WifiState:
public class WifiState {
// wifi name
private String wifiLabel;
// wifi ip
private int ipAddress;
// wifi ssid
private String ssid;
// wifi password
private String password;
// card no
private String cardNo;
// 类型
private WifiType wifiType;
// wifi 类型
public enum WifiType {
CMCC(1),
CHINANET(2),
COMMON(3);
private final int type;
private WifiType(int type) {
this.type = type;
}
public int getType() {
return type;
}
public static WifiTypegetType(int wifiType) {
WifiTypetype = null;
if(WifiType.CMCC.getType() == wifiType) {
type = WifiType.CMCC;
}
else if(WifiType.CHINANET.getType() == wifiType) {
type = WifiType.CHINANET;
}
else if(WifiType.COMMON.getType() == wifiType) {
type = WifiType.COMMON;
}
return type;
}
}
public int getIpAddress() {
return ipAddress;
}
public void setIpAddress(int ipAddress) {
this.ipAddress = ipAddress;
}
public String getSsid() {
return ssid;
}
public void setSsid(String ssid) {
this.ssid = ssid;
}
public String getPassword() {
return password;
}
public voidsetPassword(String password) {
this.password = password;
}
public String getCardNo() {
return cardNo;
}
public void setCardNo(StringcardNo) {
this.cardNo = cardNo;
}
public String getWifiLabel() {
return wifiLabel;
}
public voidsetWifiLabel(String wifiLabel) {
this.wifiLabel = wifiLabel;
}
public WifiType getWifiType() {
return wifiType;
}
public voidsetWifiType(WifiType wifiType) {
this.wifiType = wifiType;
}
}
WifiConnectStrategyListener:
/**
* wifi链接的监听
*/
public interfaceWifiConnectStrategyListener {
public voidcmccConnResult(String state);
public voidchinanetConnResult(String state);
public voidcommonConnResult(String state);
}
好了,运行下代码,页面效果如下:
当我们点击对应的按钮链接网络时,会在输出日志打印对应的wifi链接以及链接成功,当然,这是只是模拟实现,实际上整个过程没这么简单,比如需要先获得卡号,然后异步链接,获得返回的信息,链接是否成功等。
日志如下:
好了,到这里,策略模式的介绍就完成了,稍后会把项目代码上传,希望对大家有帮助。
技术交流群:179914858
原文地址:http://blog.csdn.net/why_2012_gogo/article/details/45270101