设计模式

  |   0 评论   |   0 浏览

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);
    }
}

标题:设计模式
作者:码农路上
地址:http://wujingjian.club/articles/2021/05/13/1620903952530.html