一、策略模式
(1)介绍
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,将它们封装在具有公共接口的一系列策略类中,并使它们可以相互替换。这样,算法可以独立于使用它的客户而变化。下面是关于策略模式的详细介绍:
定义:
策略模式允许你定义一系列算法,并将每个算法封装起来,使它们可以互换使用。这种模式使算法的变更独立于使用算法的客户。
涉及到的关键类或接口:
- Context(环境类):维护一个策略类的引用,负责与具体的策略类交互。
- Strategy(抽象策略类):定义所有支持的算法的公共接口。通常是一个接口或抽象类。
- ConcreteStrategy(具体策略类):实现具体的算法。
优点:
- 提高代码的复用性和可维护性。
- 算法可以在运行时动态替换,提高程序的灵活性。
- 符合开闭原则(对扩展开放,对修改关闭),新增算法无需修改现有代码。
缺点:
- 客户端需要知道所有的策略类,并选择合适的策略。
- 如果策略类较多,会导致类的数量增多,增加系统的复杂度。
适用场景:
- 当一个系统中存在多个类,它们的行为或算法不同时。
- 当一个类定义了多种行为,且这些行为以多个条件语句的形式出现时,可以用策略模式来替换条件语句。
- 当系统需要动态地在几种算法中选择一种时。
在Java源代码或开源框架中的实际应用:
策略模式在Java中的应用非常广泛,例如:
- 在排序工具中,根据用户需求选择不同的排序算法(如快速排序、归并排序等)。
- 在电子商务平台中,根据用户的会员等级计算折扣。
- 在表单验证工具中,根据不同的验证规则采用不同的验证策略(如长度验证、格式验证等)。
以下是一个简单的策略模式示例,演示了如何在Java中使用策略模式定义不同的排序算法,并在不同的场景下使用它们:
// 策略接口
public interface SortingStrategy {
void sort(int[] numbers);
}
// 具体策略类
public class BubbleSortStrategy implements SortingStrategy {
@Override
public void sort(int[] numbers) {
// 实现冒泡排序算法
}
}
public class QuickSortStrategy implements SortingStrategy {
@Override
public void sort(int[] numbers) {
// 实现快速排序算法
}
}
// 环境类
public class SortingContext {
private SortingStrategy strategy;
public void setStrategy(SortingStrategy strategy) {
this.strategy = strategy;
}
public void sort(int[] numbers) {
if (strategy != null) {
strategy.sort(numbers);
} else {
throw new IllegalStateException("Sorting strategy not set.");
}
}
}
// 使用策略模式
public class Main {
public static void main(String[] args) {
SortingContext context = new SortingContext();
int[] numbers = {
3, 1, 4, 1, 5, 9};
context.setStrategy(new BubbleSortStrategy());
context.sort(numbers);
context.setStrategy(new QuickSortStrategy());
context.sort(numbers);
}
}
这个例子中,SortingStrategy
是策略接口,BubbleSortStrategy
和 QuickSortStrategy
是具体的策略实现,SortingContext
是环境类,负责调用策略方法。Main
类演示了如何使用环境类和策略对象来执行排序操作。
(2)具体例子
package strategy;
/**
* @注释 定义一个策略接口
*/
public interface IStrategy {
// 每一个策略都是一个可执行的算法
void operate();
}
定义具体的策略
public class BlockEnemy implements IStrategy{
@Override
public void operate() {
System.out.println("孙夫人断后,挡住追兵");
}
}
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 Context {
private final IStrategy strategy;
public Context(IStrategy strategy){
this.strategy = strategy;
}
public void operate(){
// 调用具体策略的方法
strategy.operate();
}
}
策略的执行者
public class ZhaoYun {
public static void main(String[] args) {
Context context;
// 使用某个具体的策略
context = new Context(new BlockEnemy());
context.operate();
}
}
二、代理模式
(1)介绍
代理模式(Proxy Pattern)是一种常用的软件设计模式。在这种模式中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式,因为这种模式在已有的对象上提供了一个代理以控制对这个对象的访问。
定义:
代理模式为其他对象提供一种代理以控制对这个对象的访问。
涉及到的关键类或接口:
- Subject(抽象主题角色):定义了RealSubject和Proxy共用的接口,这样在任何使用RealSubject的地方都可以使用Proxy。
- RealSubject(真实主题角色):定义了Proxy所代表的真实对象。
- Proxy(代理角色):包含对真实对象的引用,从而可以操作真实对象;同时Proxy也可以附加其他操作,相当于对真实对象进行封装。
优点:
- 代理模式能够将代理对象与真实被调用的目标对象分离,一定程度上降低了系统的耦合度,增加了程序的扩展性。
- 通过代理可以控制对真实对象的使用权限。
缺点:
- 由于在客户端和真实主题之间增加了代理对象,可能会造成请求的处理速度变慢。
- 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
适用场景:
- 当需要为一个对象在不同的地址空间提供局部代表时,可以使用远程代理。
- 当需要按照需要创建开销很大的对象时,可以使用虚拟代理。
- 当需要控制对原始对象的访问时,可以使用保护代理。
- 当需要对原始对象的访问进行附加操作时,可以使用智能引用代理。
在Java源代码或开源框架中的实际应用:
在Java中,代理模式的应用非常广泛,例如:
- 在Spring框架中,AOP(面向切面编程)就是通过代理模式实现的。
- 在一些RPC(远程过程调用)框架中,如RMI,客户端通过代理对象来进行远程方法调用。
以下是一个简单的Java代理模式的代码示例:
// 抽象主题角色
public interface Subject {
void request();
}
// 真实主题角色
public class RealSubject implements Subject {
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 代理角色
public class Proxy implements Subject {
private RealSubject realSubject;
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
public void request() {
System.out.println("Proxy: Checking access prior to firing a real request.");
realSubject.request();
System.out.println("Proxy: Log after request.");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
RealSubject real = new RealSubject();
Proxy proxy = new Proxy(real);
proxy.request();
}
}
在这个例子中,Subject
是一个接口,RealSubject
是实现该接口的真实类,而 Proxy
也实现了 Subject
接口,并在内部维护了一个 RealSubject
对象的引用。这样,Proxy
可以在调用 RealSubject
的 request
方法前后执行一些附加操作,比如权限检查和日志记录等。
(2)具体例子
/**
* @注释 定义一个接口,代理类和被代理类都要实现接口中的方法
*/
public interface KindWomen {
//这种类型的女人能做什么事情呢?
public void makeEyesWithMan(); //抛媚眼
public void happyWithMan();
}
package proxy;
/**
* @注释 被代理类
*/
public class PanJinLian implements KindWomen{
@Override
public void makeEyesWithMan() {
System.out.println("潘金莲抛媚眼");
}
@Override
public void happyWithMan() {
System.out.println("潘金莲在和男人做那个.....");
}
}
package proxy;
/**
* @注释 定义代理类
*/
public class WangPo implements KindWomen{
private final KindWomen kindWomen;
public WangPo(){
//默认的话,是潘金莲的代理
this.kindWomen = new PanJinLian();
}
//她可以是KindWomen的任何一个女人的代理,只要你是这一类型
public WangPo(KindWomen kindWomen){
this.kindWomen = kindWomen;
}
/**
* 实际执行被代理类中的方法
*/
@Override
public void makeEyesWithMan() {
kindWomen.makeEyesWithMan();
}
@Override
public void happyWithMan() {
kindWomen.happyWithMan();
}
}
/**
* @注释 代理模式就是:代理类和被代理类都要实现同一个接口中的方法,即具有相同的行为
*/
public class XiMenQing {
public static void main(String[] args) {
// 实例化代理类,代理执行被代理类中的方法
WangPo wangPo = new WangPo();
wangPo.makeEyesWithMan();
wangPo.happyWithMan();
}
}
四、多例模式
package multition;
import java.util.ArrayList;
import java.util.Random;
/**
* 多例模式
*/
@SuppressWarnings("all")
public class Emperor {
private static int maxNumOfEmperor = 2; //最多只能有两个皇帝
private static ArrayList emperorInfoList = new ArrayList(maxNumOfEmperor); // 皇帝叫什么名字
private static ArrayList emperorList = new ArrayList(maxNumOfEmperor); //装皇帝的列表;
private static int countNumOfEmperor = 0; //正在被人尊称的是那个皇帝
//先把2个皇帝产生出来
static {
//把所有的皇帝都产生出来
for (int i = 0; i < maxNumOfEmperor; i++) {
emperorList.add(new Emperor("皇" + (i + 1) + "帝"));
}
}
//就这么多皇帝了,不允许再推举一个皇帝(new 一个皇帝)
private Emperor() {
//世俗和道德约束你,目的就是不让你产生第二个皇帝
}
private Emperor(String info) {
emperorInfoList.add