设计模式
1.简单工厂
传参数,告诉方法要创建什么样的对象:
- 1.1 接口
/**
* 接口的定义,该接口可以通过简单工厂来创建
*/
public interface Api {
//具体功能方法的定义
public void operation(String str);
}
- 1.2 实现类
/**
* 接口的具体实现对象A
* @author Peter
*/
public class ImplA implements Api {
public void operation(String str) {
System.out.println("ImplA s == " + str);
}
}
/**
* 接口的具体实现对象B
* @author Peter
*/
public class ImplB implements Api {
public void operation(String str) {
System.out.println("ImplB s == " + str);
}
}
- 1.3 工厂类(静态方法)
/**
* 工厂类用于创建Api对象
* @author Peter
*/
public class Factory {
//具体创建Api对象的方法,int condition示意,从外部传入的选择条件
public static Api createApi(int condition){
/**
* 应该根据某些条件去选择究竟创建哪一个具体的实现对象
* 这些条件可以从外部传入,也可以从其他途径获取
* 如果只有一个实现,可以省略条件,因为没有选择的必要
*/
Api api = null;
if(condition == 1){
api = new ImplA();
}else if(condition == 2){
api = new ImplB();
}
return api;
}
}
- 1.4 测试类
/**
* 客户端,使用Api接口
* @author Peter
*/
public class Client {
public static void main(String[] args) {
//通过简单工厂来获取接口对象
Api api = Factory.createApi(1);
api.operation("正在使用简单工厂,选择条件为1");
}
}
简单工厂当需要新增一个类时候,就需要修改工厂类,违反了开闭原则。于是出现了工厂方法模式.
2. 工厂方法
定义一个用于创建对象的接口,让子类决定实例化哪一个类,让一个类的实例化延迟到子类中。
- 2.1 接口类
public interface IFrutis {
void buy();
}
- 2.2 实现类
public class Banana implements IFrutis{
@Override
public void buy() {
System.out.println("欢迎来买香蕉");
}
}
public class Apple implements IFrutis{
@Override
public void buy() {
System.out.println("欢迎来买苹果");
}
}
- 2.3 工厂接口
public interface IFruitFactory {
IFrutis createFactory();
}
- 2.4 工厂接口实现子类
public class BananaFactory implements IFruitFactory {
@Override
public IFrutis createFactory() {
return new Banana();
}
}
public class AppleFactory implements IFruitFactory {
@Override
public IFrutis createFactory() {
return new Apple();
}
}
- 2.5 测试类
public class StudentTest {
public static void main(String[] args) {
//根据 需求的水果 生成 实体工厂
//创建香蕉工厂
IFruitFactory iFruitFactory = new BananaFactory();
//实体工厂
IFrutis banana = iFruitFactory.createFactory();
banana.buy();
IFruitFactory iFruitFactory1 = new AppleFactory();
IFrutis factory = iFruitFactory1.createFactory();
factory.buy();
}
}
缺点:增加一款产品,就要增加一个工厂类。
3 抽象工厂
- 3.1 接口类1
package factory.simple;
/**
* 抽象产品角色 交通工具接口
*
* @author lilin
*
*/
public interface Car {
/**
* 上班函数
*/
void gotowork();
}
- 3.2 接口类2
package factory.abstractfactory;
/**
* @author lilin
*
*/
public interface IBreakFast {
/**
* 吃早餐
*/
void eat();
}
- 3.3 接口1实现类
package factory.simple;
/**
* 具体产品角色,自行车
*
* @author lilin
*
*/
public class Bike implements Car {
@Override
public void gotowork() {
System.out.println("骑自行车去上班!");
}
}
package factory.simple;
/**
* @author lilin
*
*/
public class Bus implements Car {
@Override
public void gotowork() {
System.out.println("坐公交车去上班!");
}
}
- 3.4 接口2实现类
/**
*
*/
package factory.abstractfactory;
/**
* @author lilin
*
*/
public class Milk implements IBreakFast {
@Override
public void eat() {
System.out.println("喝牛奶!");
}
}
/**
*
*/
package factory.abstractfactory;
/**
* @author lilin
*
*/
public class Orange implements IBreakFast {
@Override
public void eat() {
System.out.println("吃橘子!");
}
}
- 3.5 抽象工厂接口(其中包含上述两个接口对象的生成方法定义)
/**
*
*/
package factory.abstractfactory;
import factory.simple.Car;
/**
* @author lilin
*
*/
public interface IAbstractFactory {
/**
*
* @return
*/
Car getCar();
/**
*
*/
IBreakFast getBreakFast();
}
- 3.6 工厂接口的具体实现类
抽象工厂生产类
/**
*
*/
package factory.abstractfactory;
import factory.simple.Bike;
import factory.simple.Car;
/**
* @author lilin
*
*/
public class LowPersonFactory implements IAbstractFactory {
@Override
public Car getCar() {
return new Bike();
}
@Override
public IBreakFast getBreakFast() {
return new Orange();
}
}
/**
*
*/
package factory.abstractfactory;
import factory.simple.Bus;
import factory.simple.Car;
/**
* @author lilin
*
*/
public class HighPersonFactory implements IAbstractFactory {
@Override
public Car getCar() {
return new Bus();
}
@Override
public IBreakFast getBreakFast() {
return new Milk();
}
}
- 3.7 测试类
/**
*
*/
package factory.abstractfactory;
import org.testng.annotations.Test;
import factory.simple.Car;
/**
* @author lilin
*
*/
public class AbstractFactoryTest {
@Test
public void test() {
IAbstractFactory factory = new LowPersonFactory();
Car car = factory.getCar();
IBreakFast breakFast = factory.getBreakFast();
System.out.println("吃的早饭是:");
breakFast.eat();
System.out.println("上班交通工具是:");
car.gotowork();
IAbstractFactory factory2 = new HighPersonFactory();
car = factory2.getCar();
breakFast = factory2.getBreakFast();
System.out.println("吃的早饭是:");
breakFast.eat();
System.out.println("上班交通工具是:");
car.gotowork();
}
}
- 3.8 工厂方法与抽象工厂的区别:
参考: https://blog.csdn.net/liu88010988/article/details/50799902
首先来看看这两者的定义区别:
工厂模式:定义一个用于创建对象的借口,让子类决定实例化哪一个类
抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类
个人觉得这个区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。再通俗深化理解下:工厂模式针对的是一个产品等级结构 ,抽象工厂模式针对的是面向多个产品等级结构的。
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。
它与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。
在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。
再来看看工厂方法模式与抽象工厂模式对比:
| 工厂方法模式 | 抽象工厂模式 |
| - | - |
| 针对的是一个产品等级结构 | 针对的是面向多个产品等级结构 |
| 一个抽象产品类 | 多个抽象产品类 |
| 可以派生出多个具体产品类 | 每个抽象产品类可以派生出多个具体产品类 |
| 一个抽象工厂类,可以派生出多个具体工厂类 | 一个抽象工厂类,可以派生出多个具体工厂类 |
| 每个具体工厂类只能创建一个具体产品类的实例 | 每个具体工厂类可以创建多个具体产品类的实例 |
4 模板方法
- 4.1 抽象类
package template.father;
/**
* 模板设计模式
*
* 抽取一个抽象模板类,同时定义模板方法 对于模板方法的实现,在子类中去实现
*
*
*/
public abstract class GetTimeTemplate {
// 固定流程方法
public long getTime() {
// 获取起始时间
long t1 = System.currentTimeMillis();
// 模板方法
code();
// 获取结束时间
long t2 = System.currentTimeMillis();
return t2 - t1;
}
// 钩子方法
public abstract void code();
}
- 4.2 子类
package template.son;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import template.father.GetTimeTemplate;
public class CopyFileDemo extends GetTimeTemplate {
@Override
public void code() {
//复制文件
try {
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("张三.jpg"));
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("mn.jpg"));
byte[] bs = new byte[256];
int len = 0;
while((len = inputStream.read(bs)) != -1){
outputStream.write(bs, 0, len);
outputStream.flush();
}
//释放资源
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package template.son;
import template.father.GetTimeTemplate;
public class ForDemo extends GetTimeTemplate{
@Override
public void code() {
//输出for循环
for (int i = 0; i < 10000; i++) {
System.out.println(i);
}
}
}
- 4.3 测试类
package template;
import template.father.GetTimeTemplate;
import template.son.CopyFileDemo;
import template.son.ForDemo;
public class TemplateTest {
public static void main(String[] args) {
/*GetTime time = new GetTime();
System.out.println("耗时 "+time.getTime()+" 毫秒");*/
GetTimeTemplate time = new ForDemo();
System.out.println("耗时 "+time.getTime()+" 毫秒");
GetTimeTemplate time2 = new CopyFileDemo();
System.out.println("耗时 "+time2.getTime()+" 毫秒");
}
}
5 策略模式
什么是策略模式?
类似于锦囊妙计,对外来说,这些精囊妙计长得完全一样
策略模式的组成?
* 抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
* 具体策略角色:包装了相关的算法和行为。
* 环境角色:持有一个策略类的引用,最终给客户端调用。
应用场景:
1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
3、 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
案例演示:
抽象策略类:TravelStrategy
具体策略类:AirPlanelStrategy、TrainStrategy、BicycleStrategy
环境角色:PersonContext
测试类:TestStrategyPattern
- 5.1 接口
package strategy.abs;
/**
* 抽象策略类
* @author think
*/
public interface TravelStrategy {
//出行方式
void travelWay();
boolean isOK(int type);
}
- 5.2 接口实现类
package strategy.concrete;
import strategy.abs.TravelStrategy;
/***
* 具体策略类(ConcreteStrategy)
* @author think
*
*/
public class AirPlanelStrategy implements TravelStrategy {
@Override
public void travelWay() {
System.out.println("旅游方式选择:乘坐飞机");
}
@Override
public boolean isOK(int type) {
if (type <= 10000 && type >1000) {
return true;
}
return false;
}
}
package strategy.concrete;
import strategy.abs.TravelStrategy;
/***
* 具体策略类(ConcreteStrategy)
*
* @author think
*
*/
public class BicycleStrategy implements TravelStrategy {
@Override
public void travelWay() {
System.out.println("旅游方式选择:骑自行车");
}
@Override
public boolean isOK(int type) {
if (type <= 50) {
return true;
}
return false;
}
}
package strategy.concrete;
import strategy.abs.TravelStrategy;
/***
* 具体策略类(ConcreteStrategy)
*
* @author think
*
*/
public class TrainStrategy implements TravelStrategy {
@Override
public void travelWay() {
System.out.println("旅游方式选择:乘坐火车");
}
@Override
public boolean isOK(int type) {
if (type >= 50 && type < 1000) {
return true;
}
return false;
}
}
- 5.3 环境类Context
package strategy;
import java.util.ArrayList;
import java.util.List;
import strategy.abs.TravelStrategy;
import strategy.concrete.AirPlanelStrategy;
import strategy.concrete.BicycleStrategy;
import strategy.concrete.TrainStrategy;
/**
* 环境类(Context)
*
* @author think
*
*/
public class PersonContext {
// 拥有一个出行策略引用
private List<TravelStrategy> strategylist;
public PersonContext() {
this.strategylist = new ArrayList<>();
strategylist.add(new AirPlanelStrategy());
strategylist.add(new TrainStrategy());
strategylist.add(new BicycleStrategy());
}
public void travel(int type) {
// 根据具体策略类,执行对应的出行策略
/*for (TravelStrategy travelStrategy : strategylist) {
if (travelStrategy.isOK(type)) {
travelStrategy.travelWay();
break;
}
}*/
for (TravelStrategy travelStrategy : strategylist) {
if (travelStrategy.isOK(type)) {
travelStrategy.travelWay();
break;
}
}
}
}
- 5.4 测试类
package strategy;
import org.junit.Test;
/**
* 测试类
*
* @author think
*
*/
public class StrategyTest {
@Test
public void test() {
// 环境类
PersonContext person = new PersonContext();
// 太远了,需要做飞机
person.travel(10000);
// 不太远,飞机太贵,选择火车
person.travel(100);
// 很近,直接选择自行车
person.travel(1);
}
}
6 delegage代理模式
* delegate委托模式或者叫委派模式
* delegate模式,不在23种设计模式之内,但是使用这种模式的应用很多。
* delegate模式的表现:看似是一个对象完成的功能,但是实质上通过两个对象去实现一个功能。
比如说项目经理和开发人员的关系,客户只告诉项目经理说做什么需求,但是项目经理没有真正自己去实现该需求,是安排开发人员去实现需求
* delegate模式需要的两个对象之间没有关系。
- 6.1 真正干活的类
package delegate;
public class Developer {
public void development() {
System.out.println("又来新需求了,开干");
}
}
- 6.2 委托类
package delegate;
//委托人
public class ProjectManager {
//受托人
private Developer delegate;
public Developer getDelegate() {
return delegate;
}
public void setDelegate(Developer delegate) {
this.delegate = delegate;
}
public void doSomething() {
//根据需求,将实际工作派发给开发人员或者其他人员
delegate.development();
}
}
- 6.3 测试类
package delegate;
import org.junit.Test;
public class DelegateTest {
public static void main(String args[]) {
// 成绩是委托人的,干活的是受托人的
// 对于客户端来说,是感受不到受托人的
ProjectManager pm = new ProjectManager();
pm.setDelegate(new Developer());
pm.doSomething();
}
}
7 装饰模式
装饰模式(decorate):只是在原有的bean外面添加了新的功能。
接口:PhoneInterface
目标类:HuaWeiPhone
装饰类:HuaWeiPhoneDecorate,需要持有一个目标类的引用
测试类
装饰模式在spring中的具体体现都是通过xxxWrapper类去体现的。
- 7.1 接口
package decorate;
/**
* 手机接口
* @author think
*
*/
public interface PhoneInterface {
void call();
}
- 7.2 目标类(接口实现类)
package decorate;
/**
* 目标类
* @author think
*
*/
public class HuaWeiPhone implements PhoneInterface {
@Override
public void call() {
System.out.println("使用华为手机打电话");
}
}
- 7.3 装饰类
package decorate;
/**
* 装饰模式
*
* 1:装饰类,需要去实现被装饰类接口 2:装饰类的本质是对已有的类进行功能增强
*
* 特点: 1:外表看起来是被装饰类的接口表示形式 2:内在其实使用的是被装饰类本身的功能,只是在此基础之上进行增强。
*
* @author 怡吾宇
*
*/
public class HuaWeiPhoneDecorate implements PhoneInterface {
// 被装饰的类的实例,该实例由外部传入
private PhoneInterface phone;
// 通过构造方法传入被装饰类的实例
public HuaWeiPhoneDecorate(PhoneInterface phone) {
this.phone = phone;
}
// 对被装饰类的打电话功能进行装饰,使其功能增强
@Override
public void call() {
// 依然使用的是被装饰类的手机去打电话
phone.call();
// 通过装饰扩展的新功能
System.out.println("拍照贼NB");
}
}
- 7.4 测试类
package decorate;
public class DesignPatternDemo {
public static void main(String[] args) {
PhoneInterface phone = new HuaWeiPhone();
phone.call();
System.out.println("===========");
//Phone phone2 = new PhoneDecorate(new IPhone());
PhoneInterface phone2 = new HuaWeiPhoneDecorate(phone);
phone2.call();
}
}
8 构建者模式
- 8.1 基础类
package build.product;
public class Father {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package build.product;
// 产品类
public class Student {
private int id;
private String name;
private int age;
// 子产品
private Father father;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Father getFather() {
return father;
}
public void setFather(Father father) {
this.father = father;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + ", father=" + father + "]";
}
}
- 8.2 构建器
package build.builder;
import build.product.Father;
import build.product.Student;
// 构建器
public class StudentBuilder {
// 需要构建的对象
private Student student = new Student();
public StudentBuilder id(int id) {
student.setId(id);
return this;
}
public StudentBuilder name(String name) {
student.setName(name);
return this;
}
public StudentBuilder age(int age) {
student.setAge(age);
return this;
}
public StudentBuilder father(String fatherName) {
Father father = new Father();
father.setName(fatherName);
student.setFather(father);
return this;
}
// 构建对象
public Student build() {
return student;
}
}
- 8.3 测试类
package build.director;
import build.builder.StudentBuilder;
import build.product.Student;
// 导演类/测试类
public class BuildDemo {
public static void main(String[] args) {
StudentBuilder builder = new StudentBuilder();
// 决定如何创建一个Student
builder.age(18).name("dili").father("wangjianlin");
//根据不同的表示去创建对象(私人定制)
Student student = builder.build();
//builder.build(xxxxxxxx).build();
System.out.println(student);
}
}
9 适配器模式
适配器模式(adapter)
作用:将一个类的接口转换成另外一个客户希望的接口
Adaptee:被适配的类 适配器 目标接口
将HttpRequestHandler类型---HttpRequestHandlerAdapter----转成HandlerAdapter类型
将SimpleControllerHandler类型---SimpleControllerHandlerAdapter----转成HandlerAdapter类型
ThinkPad电脑的15V充电电压---ThinkPad电脑的电源适配器-----220V电压(插座就只认识220V电压)
适配器模式分为两种:类的适配器模式、对象的适配器模式
类的适配器模式是基于继承的
对象的适配器模式是基于组合模式或者委托模式
角色:
目标接口:客户希望看到的统一接口
Adaptee:被适配的类
Adapter:适配器
也就是说,Adapter需要实现目标接口,并且拥有Adaptee的引用
interface Target{
m1();
}
class Adapter1 implements Target{
Adaptee1 adaptee1;
m1(){
adaptee1.method();
}
}
class Adapter2 implements Target{
Adaptee2 adaptee2;
m1(){
adaptee2.method();
}
}
解决的问题就是一个标准和另一个标准不兼容的问题。
解决方案有两种:
1、一个标准去匹配另一个标准
2、两个不兼容的标准,去找到一个兼容的标准
背景:一个中国人去德国出差,住在德国宾馆中,此时想充电,德国的旅馆都是针对国际标准进行设计的
问题:中国的充电器是针对三孔插孔进行设计的,而德国的充电器都是针对两孔插孔进行设计的。
需要做的事:
1、使用针对德国标准的插孔,准备一个转换插头
2、重新整一个国际标准的插孔,中国可以使用、德国也可以使用
- 9.1 接口
package adapter.target;
/**
* 国际标准
* @author think
*
*/
public interface GuoJiSocket {
void method();
}
package adapter.adaptee;
public interface DBSocket {
void method();
}
package adapter.adaptee;
public interface ZGSocket {
public void method();
}
- 9.2 接口实现类
package adapter.adaptee;
public class DSocketImpl implements DBSocket {
@Override
public void method() {
System.out.println("德国插座是使用两个眼的");
}
}
package adapter.adaptee;
public class ZGSocketImpl implements ZGSocket {
@Override
public void method() {
System.out.println("中国插座使用三眼插孔");
}
}
- 9.3 适配器
package adapter.adapter;
import adapter.adaptee.DBSocket;
import adapter.target.GuoJiSocket;
/**
* 适配器模式
*
* 主要作用:将一个类的接口转换成另外一个客户希望的接口
*
* 这个类就相当于实际案例中的电源转换头
*
*/
//DBSocket 适配的目标接口
public class DBSocketGuojiSocketAdapter implements GuoJiSocket{
//被适配的接口
private DBSocket dbSocket;
public DBSocketGuojiSocketAdapter(DBSocket dbSocket) {
this.dbSocket = dbSocket;
}
// 适配之后的方法
@Override
public void method() {
// 实质上调用德国标准
dbSocket.method();
}
}
package adapter.adapter;
import adapter.adaptee.ZGSocket;
import adapter.target.GuoJiSocket;
/**
* 适配器模式
*
* 主要作用:将一个类的接口转换成另外一个客户希望的接口
*
* 这个类就相当于实际案例中的电源转换头
*
*/
//DBSocket 适配的目标接口
public class ZGSocketGuojiSocketAdapter implements GuoJiSocket{
//被适配的接口
private ZGSocket gbSocket;
public ZGSocketGuojiSocketAdapter(ZGSocket gbSocket) {
this.gbSocket = gbSocket;
}
// 适配之后的方法
@Override
public void method() {
// 实质上调用国标
gbSocket.method();
}
}
- 9.4 使用者
package adapter;
import adapter.target.GuoJiSocket;
//使用者
public class DeGuoHotel {
//国际标准的两眼插座
private GuoJiSocket socket;
public void setGuoJiSocket(GuoJiSocket socket){
this.socket = socket;
}
// 在宾馆充电
public void charge(){
// 看起来是调用的DBSocket的标准进行充电,但是实质上是通过GBSocket完成充电
// 通过适配器将GBSocket适配成DBSocket
socket.method();
}
}
- 9.5 测试类
package adapter;
import adapter.adaptee.DBSocketImpl;
import adapter.adaptee.ZGSocketImpl;
import adapter.adapter.DBSocketGuojiSocketAdapter;
import adapter.adapter.ZGSocketGuojiSocketAdapter;
public class DesignPatternDemo {
public static void main(String[] args) {
DeGuoHotel hotel = new DeGuoHotel();
// hotel.setDBSocket(new DBSocketGuojiSocketAdapter(new DBSocketImpl()));
hotel.setGuoJiSocket(new ZGSocketGuojiSocketAdapter(new ZGSocketImpl()));
hotel.charge();
DeGuoHotel hotel1 = new DeGuoHotel();
hotel1.setGuoJiSocket(new DBSocketGuojiSocketAdapter(new DBSocketImpl()));
hotel1.charge();
}
}
10 观察者模式
- 10.1 被观察者
监听对象,通过
listeners.firePropertyChange(prop, oldValue, newValue);
监听属性的变化。
package observer;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class NewGoldHeadObservable {
//产品名称
private String productName;
//产品价格
private Double productPrice;
private PropertyChangeSupport listeners = new PropertyChangeSupport(this);
public NewGoldHeadObservable(String productName, Double productPrice) {
this.productName = productName;
this.productPrice = productPrice;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Double getProductPrice() {
return productPrice;
}
public void setProductPrice(Double productPrice) {
String oldValue = String.valueOf(this.productPrice);
this.productPrice = productPrice;
String newValue = String.valueOf(productPrice);
//发布监听事件
fireProperty(productName,oldValue,newValue);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
listeners.removePropertyChangeListener(listener);
}
protected void fireProperty(String prop, Object oldValue, Object newValue) {
listeners.firePropertyChange(prop, oldValue, newValue);
}
}
//添加观察者对象
listeners.addPropertyChangeListener(listener); //移除观察者对象 listeners.removePropertyChangeListener(listener);
进行属性变化的观察者的添加和移除。
- 10.2 观察者
在监听者一方通过实现PropertyChangeListener接口,并重写propertyChange方法。
package observer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
public class NewGoldBranchObserver implements PropertyChangeListener {
private String name;
public NewGoldBranchObserver(String name) {
this.name = name;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
String oldPrice = (String) evt.getOldValue();
String newPrice = (String) evt.getNewValue();
System.out.println("您好:" + this.name + " , " + propertyName + "的价格已经发生改变,原来的价格为:"+oldPrice+"元/克,现在的价格为:" + newPrice + "元/克");
}
}
- 10.3 测试类
package observer;
public class NewTest {
public static void main(String[] args) {
//初始化黄金连锁店 黄金产品的价格为480元每克
NewGoldHeadObservable goldHeadObservable = new NewGoldHeadObservable("黄金", 480.00);
//创建 N 个分店,并把分店添加为观察者
NewGoldBranchObserver jiujiang = new NewGoldBranchObserver("九江分店");
NewGoldBranchObserver fuyang = new NewGoldBranchObserver("阜阳分店");
goldHeadObservable.addPropertyChangeListener(jiujiang);
goldHeadObservable.addPropertyChangeListener(fuyang);
//黄金价格波动后的价格为420元每克
goldHeadObservable.setProductPrice(420.00);
System.out.println("--------------------------------------------------");
//测试移除一个监听者后,再调价格
goldHeadObservable.removePropertyChangeListener(fuyang);
goldHeadObservable.setProductPrice(430.00);
}
}
输出:
您好:九江分店 , 黄金的价格已经发生改变,原来的价格为:480.0元/克,现在的价格为:420.0元/克
您好:阜阳分店 , 黄金的价格已经发生改变,原来的价格为:480.0元/克,现在的价格为:420.0元/克
--------------------------------------------------
您好:九江分店 , 黄金的价格已经发生改变,原来的价格为:420.0元/克,现在的价格为:430.0元/克
10.4 spring观察者监听模式
- 10.4.1 目标类
package club.design;
import org.springframework.context.ApplicationEvent;
/**
* 观察者目标类
*/
public class JavaStackEvent extends ApplicationEvent {
public JavaStackEvent(Object source) {
super(source);
}
}
- 10.4.2 监听者1
package club.design;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
public class ReadListener implements ApplicationListener<JavaStackEvent> {
private String name;
private String article;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getArticle() {
return article;
}
public void setArticle(String article) {
this.article = article;
}
public ReadListener(String name) {
this.name = name;
}
@Override
@Async
public void onApplicationEvent(JavaStackEvent javaStackEvent) {
updateArticle(javaStackEvent);
}
private void updateArticle(JavaStackEvent event) {
this.article = (String) event.getSource();
System.out.printf("我是读者:%s, 文章已更新为:%s", this.name , this.article);
System.out.println();
}
}
- 10.4.3 监听者2
package club.design;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class MyEventListener {
//这里classes可以指定监听的目标对象
@EventListener(classes = {JavaStackEvent.class})
public void handleMsg(JavaStackEvent event) {
System.out.println("监听事件@EventListener,"+event.getSource());
}
}
- 10.4.4 配置监听1
package club.design;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ObserverConfiguration {
@Bean
public CommandLineRunner commandLineRunner(ApplicationContext context) {
return (args) -> {
System.out.println("发布事件:什么是观察者模式?");
context.publishEvent(new JavaStackEvent("什么是观察者模式?"));
};
}
@Bean
public ReadListener readerListener1(){
return new ReadListener("小明");
}
@Bean
public ReadListener readerListener2(){
return new ReadListener("小张");
}
@Bean
public ReadListener readerListener3(){
return new ReadListener("小爱");
}
}
- 10.4.5 发布事件
package club.design;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/person")
public class PersonController {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@GetMapping("/nihao")
public String search(String name) {
String str = "你好" + name;
applicationEventPublisher.publishEvent(new JavaStackEvent(name));
return str;
}
}
- 10.4.6 启动类
package club;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class Application implements DisposableBean {
private static ConfigurableApplicationContext ctx;
public static void main(String[] args) throws InterruptedException {
ctx = SpringApplication.run(Application.class, args);
}
@Override
public void destroy() throws Exception {
System.out.println("销毁。。。。");
if (null != ctx && ctx.isRunning()) {
ctx.close();
}
}
}
- 10.4.7 Pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
</parent>
<groupId>club.wujingjian</groupId>
<artifactId>datastructure</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
启动会打印:
发布事件:什么是观察者模式?
我是读者:小明, 文章已更新为:什么是观察者模式?
我是读者:小张, 文章已更新为:什么是观察者模式?
我是读者:小爱, 文章已更新为:什么是观察者模式?
监听事件@EventListener,什么是观察者模式?
当请求http://localhost:8080/person/nihao?name=abc
会输出
我是读者:小明, 文章已更新为:abc
我是读者:小张, 文章已更新为:abc
我是读者:小爱, 文章已更新为:abc
监听事件@EventListener,abc
11 责任链模式
责任链模式中,可以用逻辑控制只让执行链中某一个处理器执行(如下面代码),也可以每个执行器都处理,则需要控制业务逻辑代码,比如下面的执行器dealRequest()方法,中可以先执行本执行器的逻辑,然后接着调用nextHandler.dealRequest()方法.
比如A执行器
package club.design.chain;
import org.springframework.stereotype.Component;
@Component("aHandler")
public class AHandler extends Handler {
public final Integer myNum = 10;
private final int order = 1;
@Override
public String dealRequest(Integer num) {
System.out.println("num=10,A责任链处理");
//这里可以执行一些逻辑
//do something
return nextHandler.dealRequest(num);
}
}
- 11.1 接口
package club.design.chain;
public abstract class Handler {
private int order;
public Handler nextHandler;
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public Handler getNextHandler() {
return nextHandler;
}
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract String dealRequest(Integer num);
}
- 11.2 接口实现类
package club.design.chain;
import org.springframework.stereotype.Component;
@Component("aHandler")
public class AHandler extends Handler {
public final Integer myNum = 10;
private final int order = 1;
@Override
public String dealRequest(Integer num) {
if (myNum.equals(num)) {
System.out.println("num=10,A责任链处理");
} else {
//交给下个处理器
return nextHandler.dealRequest(num);
}
return "num=10,A责任链处理";
}
}
package club.design.chain;
import org.springframework.stereotype.Component;
@Component("bHandler")
public class BHandler extends Handler {
public final Integer myNum = 100;
private final int order = 2;
@Override
public String dealRequest(Integer num) {
if (myNum.equals(num)) {
System.out.println("num=100,B责任链处理");
} else {
//交给下个处理器
return nextHandler.dealRequest(num);
}
return "num=100,B责任链处理";
}
}
package club.design.chain;
import org.springframework.stereotype.Component;
@Component("cHandler")
public class CHandler extends Handler {
private final int order = 3;
@Override
public String dealRequest(Integer num) {
System.out.println("num!=10 && num!=100,C责任链处理");
return "num!=10 && num!=100,C责任链处理";
}
}
- 11.3 接口实现类枚举
package club.design.chain;
public enum HandlerBeanEnum {
AHandler("aHandler"),
BHandler("bHandler"),
CHandler("cHandler");
HandlerBeanEnum(String beanName) {
this.beanName = beanName;
}
private String beanName;
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
}
- 11.4 执行器
package club.design.chain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import java.util.LinkedList;
import java.util.List;
@Component
public class ExecuteHandler {
@Autowired
private ApplicationContext context;
private List<Handler> handlerList = new LinkedList<>();
private Handler handler ;
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
@PostConstruct
public void afterPostConstruct() {
HandlerBeanEnum[] values = HandlerBeanEnum.values();
for (HandlerBeanEnum value : values) {
Handler bean = context.getBean(value.getBeanName(), Handler.class);
handlerList.add(bean);
}
if (!CollectionUtils.isEmpty(handlerList)) {
for (int i = 1; i < handlerList.size(); i++) {
//当前处理器
Handler currentHandler = handlerList.get(i - 1);
//下一个处理器
Handler nextHandler = handlerList.get(i);
currentHandler.setNextHandler(nextHandler);
}
this.handler = handlerList.get(0);
}
}
}
- 11.5 测试类
package club.design.chain;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/chain")
public class TestController {
@Autowired
private ExecuteHandler executeHandler;
@RequestMapping("/test/{num}")
public String test(@PathVariable Integer num) {
return executeHandler.getHandler().dealRequest(num);
}
}