文档章节

设计模式(10)---->策略模式

小强斋太
 小强斋太
发布于 2016/11/09 20:07
字数 2188
阅读 0
收藏 0
点赞 0
评论 0

策略模式

一. 概述

  它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户端。

二. 模式解读

2.1 策略模式的一般化类图

2.2 模式中的角色

2.1 策略类(Stratege):定义所有支持的算法的公共接口。

2.2 具体策略类(Concrete Stratege):封装了具体的算法或行为,继承于Stratege类。

2.3 上下文类(Context):用一个ConcreteStratege来配置,维护一个对Stratege对象的引用。

2.3、代码结构

Strategy

// 策略类,定义了所有支持的算法的公共接口
public interface Strategy {
	// 策略类中支持的算法,当然还可以有更多,这里只定义了一个。
	public  void algorithm();
}

具体策略类A

public class ConcreteStrategeA implements Strategy {

	@Override
	public void algorithm() {
		System.out.println("算法A中的实现");

	}

}

具体策略类B

public class ConcreteStrategeB implements Strategy {

	@Override
	public void algorithm() {
		System.out.println("算法B中的实现");

	}

}

上下文类

// 承上启下的算法调用

class Context {
	private Strategy strategy;

	// 传入具体策略对象

	public Context(Strategy strategy) {
		this.strategy = strategy;
	}

	// 根据策略对象的值判断调用的算法类

	public void ContextInterface() {
		strategy.algorithm();
	}
}

三. 模式总结

3.1 优点

  1. 策略模式是一种定义一系列算法的方法,从概念上来看,所有算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
  2. 策略模式的Stratege类为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法的公共功能。
  3. 策略模式每个算法都有自己的类,可以通过自己的接口单独测试。因而简化了单元测试。
  4. 策略模式将具体算法或行为封装到Stratege类中,可以在使用这些类中消除条件分支(避免了不同行为堆砌到一个类中)。

3.2 缺点

    将选择具体策略的职责交给了客户端,并转给Context对象

3.3 适用场景

  • 当实现某个功能需要有不同算法要求时
  • 不同时间应用不同的业务规则时

3.4设计原则

    设计原则是把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口(c++z中可以用虚类),然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。下面是一个例子。  
    策略模式属于对象行为型模式,主要针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响 到客户端的情况下发生变化。通常,策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。

四. 应用实例1:(排序)

排序是我们经常接触到的算法,实现对一个数组的排序有很多方法,即可以采用不同的策略。下面给出了排序功能的策略模式的解决方案。

实现类图

代码

排序策略接口

public interface SortStratege {
	// 排序
	public int[] Sort(int[] array);
}

冒泡排序策略

// 冒泡排序

public class BubbleSort implements SortStratege {

	public int[] Sort(int[] array) {
		// 实现冒泡排序算法
		for (int i = 0; i < array.length; i++) {
			for (int j = i + 1; j < array.length; j++) {
				if (array[i] > array[j]) {
					int temp = array[j];
					array[j] = array[i];
					array[i] = temp;
				}
			}
		}

		return array;
	}
}

插入排序策略

//插入排序
public class InsertSort implements SortStratege {

	// 插入排序算法(递增排序)
	public int[] Sort(int[] array) {
		// 实现插入排序算法
		int temp;
		int i, j, n;
		n = array.length;

		for (i = 1; i < n; i++) {
			temp = array[i];
			for (j = i; j > 0; j--) {
				if (temp < array[j - 1])
					array[j] = array[j - 1];
				else
					break;

				array[j] = temp;
			}
		}
		return null;
	}
}

排序上下文

public class SortContext {
	private int[] m_Array;
	private SortStratege m_Stratege;

	// 初始化时将要排序的数组和排序策略传入给Context

	public SortContext(int[] array, SortStratege stratege) {
		m_Array = array;
		m_Stratege = stratege;
	}

	// 调用排序算法

	public int[] Sort() {
		int[] result = m_Stratege.Sort(this.m_Array);

		return result;
	}
}

Client

public class Client {
	public static void main(String[] args) {
		int[] array = new int[] { 12, 8, 9, 18, 22 };

		//使用冒泡排序算法进行排序
		SortStratege sortStratege = new BubbleSort();
		SortContext sorter = new SortContext(array, sortStratege);
		int[] result = sorter.Sort();
		
		for (int i : result) {
			System.out.println(i);
		}

		//使用插入排序算法进行排序
		SortStratege sortStratege2 = new InsertSort();
		SortContext sorter2 = new SortContext(array, sortStratege2);
		int[] result2 = sorter.Sort();
		
		for (int i : result2) {
			System.out.println(i);
		}

	}
}

五. 应用实例2:(诸葛亮三个锦囊)

刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是能解决棘手问题,嘿,还别说,真解决了大问题,搞到最后是周瑜陪了夫人又折兵,那咱们先看看这个场景是什么样子的。

先说说这个场景中的要素:三个妙计,一个锦囊,一个赵云,妙计是诸葛亮给的,妙计放在锦囊里,俗称就是锦囊妙计嘛,那赵云就是一个干活的人,从锦囊取出妙计,执行,然后获胜。

 

三个妙计是同一类型的东西,那咱就写个接口:

/**
 * 首先定义一个策略接口,这是诸葛亮给赵云的三个锦囊妙计的接口。
 */
public interface IStrategy {
	//每个锦囊妙计都是一个可执行的算法。
	public void operate();

}

然后再写三个实现类,有三个妙计嘛:

妙计一:初到吴国:

/**
 * 找乔国老帮忙,使孙权不能杀刘备。
 */
public class BackDoor implements IStrategy {

	@Override
	public void operate() {
		System.out.println("找乔国老帮忙,让吴国太给孙权施加压力,使孙权不能杀刘备...");
	}

}

妙计二:求吴国太开个绿灯,放行:

/**
 * 求吴国太开个绿灯。
 */
public class GivenGreenLight implements IStrategy {

	@Override
	public void operate() {
		System.out.println("求吴国太开个绿灯,放行!");

	}

}

妙计三:孙夫人断后,挡住追兵:

/**
 * 孙夫人断后,挡住追兵。
 */
public class BackEnemy implements IStrategy {

	@Override
	public void operate() {
		System.out.println("孙夫人断后,挡住追兵...");

	}

}

好了,大家看看,三个妙计是有了,那需要有个地方放妙计啊,放锦囊里:

public class Context {

	private IStrategy strategy;

	// 构造函数,要你使用哪个妙计
	public Context(IStrategy strategy) {
		this.strategy = strategy;
	}

	public void operate() {
		this.strategy.operate();
	}

}

然后就是赵云雄赳赳的揣着三个锦囊去江东使用

public class ZhaoYun {

	/**
	 * 赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计
	 */
	public static void main(String[] args) {
		Context context;

		// 刚到吴国的时候拆开第一个
		System.out.println("----------刚刚到吴国的时候拆开第一个---------------");
		context = new Context(new BackDoor());
		context.operate();// 拆开执行

		// 当刘备乐不思蜀时,拆开第二个
		System.out.println("----------刘备乐不思蜀,拆第二个了---------------");
		context = new Context(new GivenGreenLight());
		context.operate();// 拆开执行

		// 孙权的小追兵了,咋办?拆开第三个锦囊
		System.out.println("----------孙权的小追兵了,咋办?拆开第三个锦囊---------------");
		context = new Context(new BackEnemy());
		context.operate();// 拆开执行
	}

}

就这三招,搞得的周郎是“赔了夫人又折兵”呀!这就是策略模式,高内聚低耦合的特点也表现出来了,还有一个就是扩展性,也就是OCP原则,策略类可以继续添加下去气,只是修改Context.java就可以了。

六. 应用实例3:(布局管理器)

在 Java 语言中对策略模式的应用是很多的,我们这里举个布局管理器的例子。在java.awt 类库中有很多种设定好了的Container 对象的布局格式,这些格式你可以在创建软件界面的时候使用到。如果不使用策略模式,那么就没有了对布局格式扩展的可能,因为你要去修改Container 中的方法,去让它知道你这种布局格式,这显然是不可行的。

 

让我们来看看 java 源码中的实现吧。先来看看参与的类和他们扮演的角色吧。

布局管理器接口的代码:

public interface LayoutManager {
	void addLayoutComponent(String name, Component comp);

	Dimension minimumLayoutSize(Container parent);

	void layoutContainer(Container parent);
}

LayoutManager FlowLayout 就是具体的策略,代码不在

public class FlowLayout implements LayoutManager, java.io.Serializable

 

public class GridLayout implements LayoutManager, java.io.Serializable

Container

public class Container extends Component {
	
	LayoutManager layoutMgr;//对布局管理器接口的引用

	public LayoutManager getLayout() {
		return layoutMgr;
	}

	public void setLayout(LayoutManager mgr) {
		layoutMgr = mgr;
		if (valid) {
			invalidate();
		}
	}
}

可以看到,Container 根本就不关心你使用的是什么具体的布局管理器,这样也就使得Container 不会随着布局管理器的增多而修改本身。所以说策略模式是对变化的封装。

参考:

http://yangguangfu.iteye.com/blog/815107

http://www.cnblogs.com/wangjq/archive/2012/07/03/2570344.html

 

本文转载自:http://www.cnblogs.com/xqzt/archive/2013/06/04/5637058.html

共有 人打赏支持
小强斋太
粉丝 0
博文 181
码字总数 0
作品 0
广州
代理模式(Proxy Pattern):动态代理 - 最易懂的设计模式解析

前言 今天我来全面总结开发中最常用的设计模式 - 代理模式中的动态代理模式 其他设计模式介绍 1分钟全面了解“设计模式” 单例模式(Singleton) - 最易懂的设计模式解析 简单工厂模式(Sim...

Carson_Ho ⋅ 04/09 ⋅ 0

系统架构技能之设计模式-单件模式

一、开篇 其实我本来不是打算把系统架构中的一些设计模式单独抽出来讲解的,因为很多的好朋友也比较关注这方面的内容,所以我想通过我理解及平时项目中应用到的一 些常见的设计模式,拿出来给...

wbf961127 ⋅ 2017/11/12 ⋅ 0

JavaScript设计模式之观察者模式

前言 准备研究一下MVVM的一些东西,由于MVVM运用了观察者模式的思想,因此翻开了《JavaScript设计模式与开发实践》一书,将观察者模式学习了一遍,顺便有对一些常用的设计模式进行一些了解,...

Srtian ⋅ 05/22 ⋅ 0

[设计模式]简单工厂模式

简介 简单工厂模式 (Simple Factory) 又叫静态工厂方法(Static Factory Method)模式。 简单工厂模式通常是定义一个工厂类,这个类可以根据不同变量返回不同类的产品实例。 简单工厂模式是一...

静默虚空 ⋅ 2015/06/03 ⋅ 0

C#设计模式(2)——简单工厂模式

一、引言   这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理解的模式——简单工...

技术小胖子 ⋅ 2017/11/08 ⋅ 0

JavaScript 中常见设计模式整理

开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式。本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知。 JavaScript 中...

牧云云 ⋅ 05/18 ⋅ 0

设计模式梳理(一)

设计模式梳理(一) 总体来说设计模式分为三大类: @案例源码地址:https://gitlab.com/lxqxsyu/DisgnPattern 创建型模式 简单工厂模式 工厂类是整个模式的关键。它包含必要的判断逻辑,能够...

lxq_xsyu ⋅ 2017/11/02 ⋅ 0

设计模式.策略模式

策略模式跟抽象工厂非常相似,基本逻辑是根据需要实例化出需要用的类。不同的是策略模式需要调用者非常清晰的知道有哪些策略,各个策略的调用规则,而抽象工厂的话,需要知道有哪些类,找到调...

技术小胖子 ⋅ 2017/11/08 ⋅ 0

Java经典设计模式-结构型模式-适配器模式(Adapter)

适配器模式 适配器模式主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。 适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的...

Idea ⋅ 01/20 ⋅ 0

设计模式之禅(第2版).epub

【下载地址】 本书是设计模式领域公认的3本经典著作之一,“极具趣味,容易理解,但讲解又极为严谨和透彻”是本书的写作风格和方法的最大特点。第1版2010年出版,畅销至今,广受好评,是该领...

winter730 ⋅ 05/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

用ZBLOG2.3博客写读书笔记网站能创造今日头条的辉煌吗?

最近两年,著名的自媒体网站今日头条可以说是火得一塌糊涂,虽然从目前来看也遇到了一点瓶颈,毕竟发展到了一定的规模,继续增长就更加难了,但如今的今日头条规模和流量已经非常大了。 我们...

原创小博客 ⋅ 今天 ⋅ 0

MyBatis四大核心概念

本文讲解 MyBatis 四大核心概念(SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper)。 MyBatis 作为互联网数据库映射工具界的“上古神器”,训有四大“神兽”,谓之:Sql...

waylau ⋅ 今天 ⋅ 0

以太坊java开发包web3j简介

web3j(org.web3j)是Java版本的以太坊JSON RPC接口协议封装实现,如果需要将你的Java应用或安卓应用接入以太坊,或者希望用java开发一个钱包应用,那么用web3j就对了。 web3j的功能相当完整...

汇智网教程 ⋅ 今天 ⋅ 0

2个线程交替打印100以内的数字

重点提示: 线程的本质上只是一个壳子,真正的逻辑其实在“竞态条件”中。 举个例子,比如本题中的打印,那么在竞态条件中,我只需要一个方法即可; 假如我的需求是2个线程,一个+1,一个-1,...

Germmy ⋅ 今天 ⋅ 0

Springboot2 之 Spring Data Redis 实现消息队列——发布/订阅模式

一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式,这里利用redis消息“发布/订阅”来简单实现订阅者模式。 实现之前先过过 redis 发布订阅的一些基础概念和操...

Simonton ⋅ 今天 ⋅ 0

error:Could not find gradle

一.更新Android Studio后打开Project,报如下错误: Error: Could not find com.android.tools.build:gradle:2.2.1. Searched in the following locations: file:/D:/software/android/andro......

Yao--靠自己 ⋅ 昨天 ⋅ 0

Spring boot 项目打包及引入本地jar包

Spring Boot 项目打包以及引入本地Jar包 [TOC] 上篇文章提到 Maven 项目添加本地jar包的三种方式 ,本篇文章记录下在实际项目中的应用。 spring boot 打包方式 我们知道,传统应用可以将程序...

Os_yxguang ⋅ 昨天 ⋅ 0

常见数据结构(二)-树(二叉树,红黑树,B树)

本文介绍数据结构中几种常见的树:二分查找树,2-3树,红黑树,B树 写在前面 本文所有图片均截图自coursera上普林斯顿的课程《Algorithms, Part I》中的Slides 相关命题的证明可参考《算法(第...

浮躁的码农 ⋅ 昨天 ⋅ 0

android -------- 混淆打包报错 (warning - InnerClass ...)

最近做Android混淆打包遇到一些问题,Android Sdutio 3.1 版本打包的 错误如下: Android studio warning - InnerClass annotations are missing corresponding EnclosingMember annotation......

切切歆语 ⋅ 昨天 ⋅ 0

eclipse酷炫大法之设置主题、皮肤

eclipse酷炫大法 目前两款不错的eclipse 1.系统设置 Window->Preferences->General->Appearance 2.Eclipse Marketplace下载【推荐】 Help->Eclipse Marketplace->搜索‘theme’进行安装 比如......

anlve ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部