目录:
一、简单工厂模式 二、工厂方法模式 三、抽象工厂模式 四、建造者模式 五、桥接模式
六、组合模式 七、适配器模式 八、装饰者模式 九、状态模式 十、享元模式
十一、命令模式 十二、责任链模式 十三、备忘录模式 十四、观察者模式 十五、访问者模式
一、简单工厂模式
我们在实例化对象的时候通常需要用 new 关键字, 这样耦合度比较高,于是有了工厂模式,将new一个对象放到工厂中,用工厂new一个对象再给我返回
eg.包装做披萨过程
public class SimpleFactory {
//更加 orderType 返回对应的 Pizza 对象
public Pizza createPizza(String orderType) {
Pizza pizza = null;
System.out.println("使用简单工厂模式");
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName(" 希腊披萨 ");
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
pizza.setName(" 奶酪披萨 ");
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
pizza.setName("胡椒披萨");
}
return pizza;
}
public class OrderPizza {
//定义一个简单工厂对象SimpleFactory simpleFactory; Pizza pizza = null;
SimpleFactory simpleFactory;
Pizza pizza = null;
//构造器
public OrderPizza(SimpleFactory simpleFactory) {
setFactory(simpleFactory);
}
public void setFactory(SimpleFactory simpleFactory) {
String orderType = ""; //用户输入的
this.simpleFactory = simpleFactory; //设置简单工厂对象
orderType = getType();
pizza = this.simpleFactory.createPizza(orderType);
//输出 pizza
if(pizza != null) { //订购成功
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
} else {
System.out.println(" 订购披萨失败 "); break;
}
}
简单工厂模式实际上就是面向过程=>面向对象的形式,我们把过程封装在工厂容器中,别人看不到,因为做披萨的过程不需要别人知道,别人只管拿到披萨吃就行了。
二、工厂方法模式
工厂方法模式是简单工厂模式的升级版,上面的模式我们会发现一个问题:就是制作披萨的过程是相同的,只是披萨的类型不同,创建多个披萨就要写多个一样的方法,所以需要用到新的方式:创建一个抽象类,抽取共有的方法,所有的披萨继承这个抽象类,制作过程都一样,只需要在其中加入自己独有的方法就行。
- 工厂方法模式设计方案:将项目的实例化功能抽象成抽象方法,在不同的子类中具体实现。
- 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
UML:
eg.创建不同的图片工厂来读不同类型的图片
public abstract class Gj19IMGReader {
public abstract void read();
}
public class Gj19JPGReader extends Gj19IMGReader {
@Override
public void read() {
System.out.println("读jpg");
}
}
public class Gj19GIFReader extends Gj19IMGReader {
@Override
public void read() {
System.out.println("读gif");
}
}
public abstract class Gj19IMGReaderFactory {
public abstract void getGj19IMGReader(Gj19IMGReader reader);
}
public class Gj19JPGReaderFactory extends Gj19IMGReaderFactory{
@Override
public void getGj19IMGReader(Gj19IMGReader reader) {
reader.read();
}
}
public class Gj19GIFReaderFactory extends Gj19IMGReaderFactory {
@Override
public void getGj19IMGReader(Gj19IMGReader reader) {
reader.read();
}
}
public class Application {
public static void main(String[] args) {
Gj19IMGReaderFactory factory = new Gj19JPGReaderFactory();
Gj19IMGReader reader = new Gj19JPGReader();
factory.getGj19IMGReader(reader);
factory = new Gj19JPGReaderFactory();
reader = new Gj19GIFReader();
factory.getGj19IMGReader(reader);
}
}
三、抽象工厂模式
抽象工厂模式是工厂方法模式的升级版,抽象工厂模式中我们可以定义实现不止一个接口,一个工厂也可以生成不止一个产品类
相当于我要做披萨的同时做面包 ,假设两种用到的原材料都一样,所以我们可以将披萨和面包的原材料提取出来,实现不同的口味就行。
- 抽象工厂模式:定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
- 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
- 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
- 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
UML:
eg.有pc和mac两种电脑,用抽象工厂的方法打印不同类型电脑的不同类型的硬件(CPU、RAM等)
public abstract class CPU {
public abstract void show_CPU();
}
public class MacCPU extends CPU {
@Override
public void show_CPU() {
System.out.println("MacCPU");
}
}
public class PcCPU extends CPU {
@Override
public void show_CPU() {
System.out.println("PcCPU");
}
}
public abstract class RAM {
public abstract void show_RAM();
}
public class MacRAM extends RAM {
@Override
public void show_RAM() {
System.out.println("MacRAM");
}
}
public class PcRAM extends RAM {
@Override
public void show_RAM() {
System.out.println("PcRAM");
}
}
public abstract class AbstractFactory {
public abstract void createRAM();
public abstract void createCPU();
}
public class MacFactory extends AbstractFactory {
@Override
public void createRAM() {
new MacRAM().show_RAM();
}
@Override
public void createCPU() {
new MacCPU().show_CPU();
}
}
public class PcFactory extends AbstractFactory {
@Override
public void createRAM() {
new PcRAM().show_RAM();
}
@Override
public void createCPU() {
new PcCPU().show_CPU();
}
}
public class Application {
public static void main(String[] args) {
AbstractFactory factory = new PcFactory();
factory.createRAM();
factory.createCPU();
factory = new MacFactory();
factory.createRAM();
factory.createCPU();
}
}
四、建造者模式:将产品和产品建造过程解耦
传统建房子:打桩、砌墙、封顶,房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不相同的
传统建房子设计的程序结构,过于简单,没有设计缓存层对象,程序的扩展和维护不好. 也就是说,这种设计方案,把产品(即:房子) 和 创建产品的过程(即:建房子流程) 封装在一起,耦合性增强了。
UML:
- Product(产品角色): 一个具体的产品对象。
- Builder(抽象建造者): 创建一个 Product 对象的各个部件指定的 接口/抽象类。
- ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。
- Director(指挥者): 构建一个使用 Builder 接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
eg.汽车厂生产汽车,汽车包括发动机,变速箱,底盘三大件。不同厂家组装的顺序不同。现在有奔驰,宝马,奥迪三个厂家分别以不同的顺序制造汽车。
public class Car {
private String faDongJi;
private String bianSuXiang;
private String diPan;
public String getFaDongJi() {
return faDongJi;
}
public void setFaDongJi(String faDongJi) {
this.faDongJi = faDongJi;
}
public String getBianSuXiang() {
return bianSuXiang;
}
public void setBianSuXiang(String bianSuXiang) {
this.bianSuXiang = bianSuXiang;
}
public String getDiPan() {
return diPan;
}
public void setDiPan(String diPan) {
this.diPan = diPan;
}
@Override
public String toString() {
return "Car{" +
"faDongJi='" + faDongJi + '\'' +
", bianSuXiang='" + bianSuXiang + '\'' +
", diPan='" + diPan + '\'' +
'}';
}
}
public abstract class CarBuilder {
protected Car car = new Car();
public abstract void buildFaDongJi();
public abstract void buildBianSuXiang();
public abstract void buildDiPan();
public Car build(){
return car;
}
}
public class Director {
CarBuilder carBuilder;
public Director(CarBuilder carBuilder) {
this.carBuilder = carBuilder;
}
public Car constructCar(){
carBuilder.buildFaDongJi();
carBuilder.buildBianSuXiang();
carBuilder.buildDiPan();
return carBuilder.build();
}
}
public class BenChi extends CarBuilder {
@Override
public void buildFaDongJi() {
car.setFaDongJi("奔驰的发动机");
}
@Override
public void buildBianSuXiang() {
car.setBianSuXiang("奔驰的变速箱");
}
@Override
public void buildDiPan() {
car.setDiPan("奔驰的底盘");
}
}
public class BaoMa extends CarBuilder {
@Override
public void buildFaDongJi() {
car.setFaDongJi("宝马的发动机");
}
@Override
public void buildBianSuXiang() {
car.setBianSuXiang("宝马的变速箱");
}
@Override
public void buildDiPan() {
car.setDiPan("宝马的底盘");
}
}
public class AoDi extends CarBuilder {
@Override
public void buildFaDongJi() {
car.setFaDongJi("奥迪的发动机");
}
@Override
public void buildBianSuXiang() {
car.setBianSuXiang("奥迪的变速箱");
}
@Override
public void buildDiPan() {
car.setDiPan("奥迪的底盘");
}
}
public class Application {
public static void main(String[] args) {
BaoMa builder1 = new BaoMa();
Director director1 = new Director(builder1);
System.out.println(director1.constructCar());
BenChi builder2 = new BenChi();
Director director2 = new Director(builder2);
System.out.println(director2.constructCar());
AoDi builder3 = new AoDi();
Director director3 = new Director(builder3);
System.out.println(director3.constructCar());
}
}
五、桥接模式
现在对不同手机类型的不同品牌实现操作编程(比如:开机、关机、上网,打电话等)
如果我们增加手机的样式,就需要增加各个品牌手机的类,同样如果我们增加一个手机品牌,也要在各个手机样式类下增加。
这违反了单一职责原则,当我们增加手机样式时,要同时增加所有品牌的手机,这样增加了代码维护成本
桥接模式可以解决这一问题。
- Client 类:桥接模式的调用者
- 抽象类(Abstraction) :维护了 Implementor / 即它的实现类 ConcreteImplementorA…, 二者是聚合关系, Abstraction充当桥接类
- RefinedAbstraction : 是 Abstraction 抽象类的子类
- Implementor : 行为实现类的接口
- ConcreteImplementorA /B :行为的具体实现类
eg.用桥接模式画红、绿两种颜色的圆,半径、位置由构造器决定
public abstract class Shape {
DrawApi drawApi;
public Shape(DrawApi drawApi) {
this.drawApi = drawApi;
}
public abstract String draw() ;
}
public class Circle extends Shape {
private int radius;
public Circle(DrawApi drawApi, int radius) {
super(drawApi);
this.radius = radius;
}
@Override
public String draw() {
drawApi.drawCircle();
return "半径为"+(radius*2*3.14);
}
}
public interface DrawApi {
void drawCircle();
}
public class GreenCircle implements DrawApi {
@Override
public void drawCircle() {
System.out.println("绿色圆");
}
}
public class RedCircle implements DrawApi {
@Override
public void drawCircle() {
System.out.println("红色圆");
}
}
public class Application {
public static void main(String[] args) {
DrawApi draw1 = new RedCircle();
Circle circle1 = new Circle(draw1,3);
System.out.println(circle1.draw());
DrawApi draw2 = new GreenCircle();
Circle circle2 = new Circle(draw2,5);
System.out.println(circle2.draw());
}
}
六、组合模式
- Component :这是组合中对象声明接口,在适当情况下,实现所有类共有的接口默认行为,用于访问和管理Component 子部件, Component 可以是抽象类或者接口
- Leaf : 在组合中表示叶子节点,叶子节点没有子节点
- Composite :非叶子节点, 用于存储子部件, 在 Component 接口中实现子部件的相关操作,比如增加(add), 删除。
eg.使用组合模式,模拟文件系统。包含文件夹和文件,要求,文件夹里面既能放文件件又能放文件,而且实现对文件夹和文件的增加删除和打印名称的操作。
public abstract class File {
String name;
public File(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void display();
}
public class Folder extends File{
private List<File> files;
public Folder(String name){
super(name);
files = new ArrayList<File>();
}
/**
* 浏览文件夹中的文件
*/
public void display() {
for(File file : files){
file.display();
}
}
/**
* @desc 向文件夹中添加文件
* @param file
* @return void
*/
public void add(File file){
files.add(file);
}
/**
* @desc 从文件夹中删除文件
* @param file
* @return void
*/
public void remove(File file){
files.remove(file);
}
}
public class ImageFile extends File{
public ImageFile(String name) {
super(name);
}
public void display() {
System.out.println("这是图像文件,文件名:" + super.getName());
}
}
public class TextFile extends File{
public TextFile(String name) {
super(name);
}
public void display() {
System.out.println("这是文本文件,文件名:" + super.getName());
}
}
public class VideoFile extends File{
public VideoFile(String name) {
super(name);
}
public void display() {
System.out.println("这是影像文件,文件名:" + super.getName());
}
}
public class Application {
public static void main(String[] args) {
//总文件夹
Folder jwh = new Folder("总文件夹");
//向总文件夹中放入三个文件:1.txt、2.jpg、3.文件夹
TextFile text_1= new TextFile("1.txt");
ImageFile image_1 = new ImageFile("2.jpg");
Folder folder_1 = new Folder("1.文件夹");
jwh.add(text_1);
jwh.add(image_1);
jwh.add(folder_1);
//向1.文件夹中添加文件:1.1.txt、1.1.jpg、1.1.mp4
TextFile text_1_1 = new TextFile("1.1.txt");
ImageFile image_1_1 = new ImageFile("1.1.jpg");
VideoFile mp4_1_1 = new VideoFile("1.1.mp4");
folder_1.add(text_1_1);
folder_1.add(image_1_1);
folder_1.add(mp4_1_1);
System.out.println("删除前:");
//遍历1.文件夹
folder_1.display();
//将1.1.txt删除
folder_1.remove(text_1_1);
System.out.println("删除后:");
folder_1.display();
}
}
七、适配器模式
- 适配器模式:将一个类的接口转换成另一种接口.让原本接口不兼容的类可以兼容
- 从用户的角度看不到被适配者,是解耦的
- 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
eg.使用适配器模式模拟格式工厂的功能。将mp4格式的视频转换为avi格式。
public interface Avi {
void playAvi();
}
public interface Mp4 {
void playMp4();
}
public class VideoPlayer implements Mp4{
@Override
public void playMp4() {
System.out.println("播放Mp4格式的视频");
}
}
public class FormatFactory extends VideoPlayer implements Avi{
@Override
public void playAvi() {
//转换成MP4格式的视频
super.playMp4();
}
}
public class Application {
public static void main(String[] args) {
Mp4 mp4=new VideoPlayer();
mp4.playMp4();
Avi avi=new FormatFactory();
avi.playAvi();
}
}
八、装饰者模式
- 装饰者模式就像打包一个快递
主体:比如:陶瓷、衣服 (Component) // 被装饰者
包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator) - Component 主体:比如类似前面的 Drink
- ConcreteComponent 和 DecoratorConcreteComponent:具体的主体, 比如前面的各个单品咖啡
- Decorator: 装饰者,比如各调料.在如图的 Component 与 ConcreteComponent 之间,如果 ConcreteComponent 类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象层一个类。
eg.简单的手机(SimplePhone)在接收到来电的时候,会发出声音来提醒主人,而现在我们需要为该手机添加一项功能,在接收来电的时候,除了有声音,还能产生震动(JarPhone),还可以得到更加高级的手机(ComplexPhone),来电时,它不仅能够发生,产生震动,而且有灯光闪烁提示,使用装饰模式来模拟手机功能的升级过程。
public abstract class Phone {
public abstract void call();
}
public class SimplePhone extends Phone{
public SimplePhone() {
}
public void call(){
System.out.println("叮铃铃");
}
}
public class PhoneDecorator extends Phone {
private Phone phone;
public PhoneDecorator(Phone phone) {
if (phone != null) {
this.phone = phone;
} else {
this.phone = new SimplePhone();
}
}
@Override
public void call() {
phone.call();
}
}
public class JarPhone extends PhoneDecorator {
public JarPhone(Phone phone) {
super(phone);
}
public void call() {
super.call();
System.out.println("震动");
}
}
public class ComplexPhone extends PhoneDecorator {
public ComplexPhone(Phone phone) {
super(phone);
}
public void call() {
super.call();
System.out.println("灯光闪烁");
}
}
public class Application {
public static void main(String[] args) {
Phone p1 = new SimplePhone();
p1.call();
System.out.println("----");
Phone p2 = new JarPhone(p1);
p2.call();
System.out.println("----");
Phone p3 = new ComplexPhone(p2);
p3.call();
}
}
九、状态模式
- 状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换
- 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类
UML图:
- Context 类为环境角色, 用于维护 State 实例,这个实例定义当前状态
- State 是抽象状态角色,定义一个接口封装与 Context 的一个特点接口相关行为
- ConcreteState 具体的状态角色,每个子类实现一个与 Context 的一个状态相关行为
eg:京东会员包括:黑金会员,铂金会员,黄金会员,不同级别的会员买商品折扣不同。黑金会员打6折,铂金会员打7折,黄金会员打8折。要求,京东商场方面,根据不同的会员不同对待。
public interface VipStatus {
void pays();
}
public class YellowStatus implements VipStatus {
private double money;
public YellowStatus(double money) {
this.money = money * 0.8;
}
@Override
public void pays() {
System.out.println("您是黄金会员,消费了"+money+"元");
}
}
public class WhiteStatus implements VipStatus {
private double money;
public WhiteStatus(double money) {
this.money = money * 0.7;
}
@Override
public void pays() {
System.out.println("您是白金会员,消费了"+money+"元");
}
}
public class BlackStatus implements VipStatus {
private double money;
public BlackStatus(double money) {
this.money = money * 0.6;
}
@Override
public void pays() {
System.out.println("您是黑金会员,消费了"+money+"元");
}
}
public class Card {
VipStatus status;
public void showMessage(){
System.out.println("***********");
status.pays();
System.out.println("***********");
}
public void setState(VipStatus status){
this.status=status;
}
}
public class Application{
public static void main(String args[]) {
VipStatus status=new YellowStatus(1000);
Card card=new Card();
card.setState(status);
card.showMessage();
status=new WhiteStatus(1000);
card.setState(status);
card.showMessage();
status=new BlackStatus(1000);
card.setState(status);
card.showMessage();
}
}
十、享元模式
- 享元模式(Flyweight Pattern) 也叫 蝇量模式: 运用共享技术有效地支持大量细粒度的对象
- 常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
- 享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时。不需总是创建新对象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率
- 享元模式经典的应用场景就是池技术了,String 常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式
UML图:
- FlyWeight 是抽象的享元角色, 他是产品的抽象类, 同时定义出对象的外部状态和内部状态(后面介绍) 的接口或实现
- ConcreteFlyWeight 是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务
- UnSharedConcreteFlyWeight 是不可共享的角色,一般不会出现在享元工厂。
- FlyWeightFactory 享元工厂类,用于构建一个池容器(集合), 同时提供从池中获取对象方法
eg:画圆圈,颜色是内状态,半径和位置是外状态,要红黄蓝三色的圆圈,每种颜色画两个不同半径和位置的圆圈。
代码:
public class Circle {
double radius;
double location;
public Circle(double radius, double location) {
this.radius = radius;
this.location = location;
}
public double getRadius() {
return radius;
}
public double getLocation() {
return location;
}
}
public interface Paint{
void printCircle(Circle circle);
}
//具体的绘制方式
public class ConcretePaint implements Paint {
//共享的部分,内部状态
private String color;
public ConcretePaint(String color) {
this.color = color;
}
@Override
public void printCircle(Circle circle) {
System.out.println("画一个:" + color + "的圆,半径为:" + circle.getRadius() + ",位置为:" + circle.getLocation());
}
}
//圆的工厂类,根据需要返回一个圆
public class FlyweightFactory {
//集合, 充当池的作用
private HashMap<String, ConcretePaint> pool = new HashMap<>();
//根据圆的颜色,返回一个圆, 如果没有就创建一个圆,并放入到池中,并返回
public Paint getPaintCategory(String color) {
if (!pool.containsKey(color)) {
pool.put(color, new ConcretePaint(color));
}
return pool.get(color);
}
//获取圆分类的总数
public int getPaintCount() {
return pool.size();
}
}
public class Application{
public static void main(String args[]) {
FlyweightFactory factory = new FlyweightFactory();
Paint paint1 = factory.getPaintCategory("红色");
paint1.printCircle(new Circle(5,5));
paint1.printCircle(new Circle(10,10));
System.out.println("*******************");
Paint paint2 = factory.getPaintCategory("黄色");
paint2.printCircle(new Circle(5,5));
paint2.printCircle(new Circle(10,10));
System.out.println("*******************");
Paint paint3 = factory.getPaintCategory("蓝色");
paint3.printCircle(new Circle(5,5));
paint3.printCircle(new Circle(10,10));
System.out.println("*******************");
System.out.println("圆的颜色分类共" + factory.getPaintCount() + "种");
}
}
结果:
画一个:红色的圆,半径为:5.0,位置为:5.0
画一个:红色的圆,半径为:10.0,位置为:10.0
*******************
画一个:黄色的圆,半径为:5.0,位置为:5.0
画一个:黄色的圆,半径为:10.0,位置为:10.0
*******************
画一个:蓝色的圆,半径为:5.0,位置为:5.0
画一个:蓝色的圆,半径为:10.0,位置为:10.0
*******************
圆的颜色分类共3种
十一、命令模式
- 命令模式(Command Pattern):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,
我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计 - 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
- 在命名模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作。
- 通俗易懂的理解:将军发布命令,士兵去执行。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)。
Invoker 是调用者(将军),Receiver 是被调用者(士兵),MyCommand 是命令,实现了 Command 接口,持有接收对象
uml:
- Invoker 是调用者角色
- Command: 是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类
- Receiver: 接受者角色,知道如何实施和执行一个请求相关的操作
- ConcreteCommand: 将一个接受者对象与一个动作绑定,调用接受者相应的操作,实现 execute
eg.王者荣耀,控制兰陵王,当按下不同的技能键时,发出不同的技能,发出技能的形式为打印技能名称即可。要求使用命令模式编写。
//此类是Receiver,用来接收按键请求而打印不同技能
public class Skill {
public void skill_1(){
System.out.println("使用一技能");
}
public void skill_2(){
System.out.println("使用一技能");
}
public void skill_3(){
System.out.println("使用三技能");
}
}
//此类是Command,用来发起按键请求
public interface Key {
void execute();
}
//下面三个类是ConcreteCommand,用来实现具体的按键请求,即实现execute
public class KeyOne implements Key {
private Skill skill;
public KeyOne(Skill skill){
this.skill = skill;
}
public void execute() {
skill.skill_1();
}
}
public class KeyTwo implements Key {
private Skill skill;
public KeyTwo(Skill skill){
this.skill = skill;
}
public void execute() {
skill.skill_2();
}
}
public class KeyThree implements Key {
private Skill skill;
public KeyThree(Skill skill){
this.skill = skill;
}
public void execute() {
skill.skill_3();
}
}
//此类是Invoker,将三个键都存入集合中,再通过placeKeys直接调用三个按键方法
public class LanLinWang {
private List<Key> keyList = new ArrayList<>();
public void takeKey(Key key){
keyList.add(key);
}
public void placeKeys(){
for (Key key : keyList) {
key.execute();
}
keyList.clear();
}
}
//总结:将三个技能对应添加到按键中,再通过兰陵王将按键存入集合中,通过方法调用按键,也就能调用相应技能
public class Application {
public static void main(String[] args) {
Skill skill = new Skill();
KeyOne keyOne = new KeyOne(skill);
KeyTwo keyTwo = new KeyTwo(skill);
KeyThree keyThree = new KeyThree(skill);
LanLinWang lanLinWang= new LanLinWang();
lanLinWang.takeKey(keyOne);
lanLinWang.takeKey(keyTwo);
lanLinWang.takeKey(keyThree);
lanLinWang.placeKeys();
}
}
输出
使用一技能
使用一技能
使用三技能
十二、责任链模式
- 职责链模式(Chain of Responsibility Pattern), 又叫 责任链模式,为请求创建了一个接收者对象的链(简单示意图)。这种模式对请求的发送者和接收者进行解耦。
- 职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
- 这种类型的设计模式属于行为型模式
uml:
- Handler : 抽象的处理者, 定义了一个处理请求的接口, 同时含义另外 Handler
- ConcreteHandlerA , B 是具体的处理者, 处理它自己负责的请求, 可以访问它的后继者(即下一个处理者), 如果可以处理当前请求,则处理,否则就将该请求交个 后继者去处理,从而形成一个职责链
- Request , 含义很多属性,表示一个请求
eg.防疫措施,10人及10人以下感染,打印“启动一级隔离措施,病房隔离”。10人以上到100人感染,打印“启动二级隔离措施,居家隔离”,10人以上到1000人感染,打印“启动三级隔离措施,方舱医院隔离”。
//相当于Handler
public interface Measures {
void handleMeasure(int number);
void setNextMeasure(Measures measures);
}
//ConcreteHandler
public class LevelOne implements Measures {
private Measures measures;
//Request
public void handleMeasure(int number){
if(number>0 && number<=10)
System.out.println("启动一级隔离措施,病房隔离");
else{
if(measures !=null)
measures.handleMeasure(number);
}
}
public void setNextMeasure(Measures measures){
this.measures = measures;
}
}
//ConcreteHandler
public class LevelTwo implements Measures {
private Measures measures;
//Request
public void handleMeasure(int number){
if(number>10 && number<=100)
System.out.println("启动二级隔离措施,居家隔离");
else{
if(measures !=null)
measures.handleMeasure(number);
}
}
public void setNextMeasure(Measures measures){
this.measures = measures;
}
}
//ConcreteHandler
public class LevelThree implements Measures {
private Measures measures;
//Request
public void handleMeasure(int number){
if(number>100 && number<=1000)
System.out.println("启动三级隔离措施,方舱医院隔离");
else{
if(measures !=null)
measures.handleMeasure(number);
}
}
public void setNextMeasure(Measures measures){
this.measures = measures;
}
}
public class Application {
public static void main(String[] args) {
LevelOne l1 = new LevelOne();
LevelTwo l2 = new LevelTwo();
LevelThree l3 = new LevelThree();
//设置责任链,相当于不满足1就找2,不满足2就找3
l1.setNextMeasure(l2);
l2.setNextMeasure(l3);
l1.handleMeasure(5);
l1.handleMeasure(55);
l1.handleMeasure(555);
}
}
输出
启动一级隔离措施,病房隔离
启动二级隔离措施,居家隔离
启动三级隔离措施,方舱医院隔离
十三、备忘录模式
基本介绍
- 备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态
- 可以这样理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情,或者是记录已经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作
- 备忘录模式属于行为型模式
uml:
- originator : 对象(需要保存状态的对象)
- Memento : 备忘录对象,负责保存好记录,即 Originator 内部状态
- Caretaker: 守护者对象,负责保存多个备忘录对象, 使用集合管理,提高效率
- 说明:如果希望保存多个 originator 对象的不同时间的状态,也可以,只需要要 HashMap <String, 集合>
eg.玩三国志,要统一天下时间很长,需要玩很多天,所以每次玩完都得存档。下次再玩的时候从存档处继续。可以使用磁盘上的文件作为存储介质, 每次存档内容为包含历史事件的字符串,例如,官渡之战,赤壁之战,三足鼎立等。
*注:本题最简单的方法可采用单个对象重复对其属性赋值(也就是重复传入不同的字符串)的方式达到重复存档读档的效果,但我采用更高级的集合形式,也就是可以存多个档,更与现实相符
//先定义一个备忘录对象用来保存历史事件,此类是备忘录模式最内部状态,即备忘录里面的应该保存的属性
public class Memento {
private String historical_event;
//有参构造器
public Memento(String historical_event) {
this.historical_event = historical_event;
}
public String getHistorical_event() {
return historical_event;
}
public void setHistorical_event(String historical_event) {
this.historical_event = historical_event;
}
}
//游戏角色,用来创建备忘录对象以及展示备忘录对象
public class GameRole {
private String historical_event;
//创建 Memento ,即根据当前的状态得到 Memento
public Memento createMemento() {
return new Memento(historical_event);
}
//从备忘录对象,恢复 GameRole 的状态
public void recoverGameRoleFromMemento(Memento memento) {
this.historical_event = memento.getHistorical_event();
}
//显示当前游戏角色的状态
public void display() {
System.out.println("玩家当前完成的历史事件为:" + this.historical_event);
}
public String getHistorical_event() {
return historical_event;
}
public void setHistorical_event(String historical_event) {
this.historical_event = historical_event;
}
}
//存档集合,用来保存多个备忘录(存档)
public class Caretaker {
//对 GameRole 保存多次状态
private List<Memento> mementos;
public Caretaker() {
mementos = new ArrayList<>();
}
public List<Memento> getMementos() {
return mementos;
}
public void addMementos(Memento memento) {
mementos.add(memento);
System.out.println("存档完成");
}
public void showMementos() {
for (Memento memento : mementos) {
System.out.println(mementos.indexOf(memento)+":"+memento.getHistorical_event());
}
}
}
//总结:GameRole 创建 Memento 对象,Caretaker 存入多个 GameRole ;Caretaker 调用 GameRole ,GameRole 再调用 Memento
//来显示存档
public class Client {
public static void main(String[] args) {
//创建游戏角色,完成官渡之战
GameRole gameRole = new GameRole();
gameRole.setHistorical_event("官渡之战");
gameRole.display();
//把当前状态保存 caretaker
Caretaker caretaker = new Caretaker();
caretaker.addMementos(gameRole.createMemento());
//游戏角色完成赤壁之战
gameRole.setHistorical_event("赤壁之战");
gameRole.display();
//把当前状态保存 caretaker
caretaker.addMementos(gameRole.createMemento());
//游戏角色完成三足鼎立
gameRole.setHistorical_event("三足鼎立");
gameRole.display();
//把当前状态保存 caretaker
caretaker.addMementos(gameRole.createMemento());
System.out.println("--------------");
System.out.println("查看所有存档:");
caretaker.showMementos();
System.out.println("--------------");
Scanner sc = new Scanner(System.in);
System.out.println("请输入要恢复的存档索引:");
int index = sc.nextInt();
gameRole.recoverGameRoleFromMemento(caretaker.getMementos().get(index));
System.out.println("恢复后的状态");
gameRole.display();
}
}
输出:
玩家当前完成的历史事件为:官渡之战
存档完成
玩家当前完成的历史事件为:赤壁之战
存档完成
玩家当前完成的历史事件为:三足鼎立
存档完成
--------------
查看所有存档:
0:官渡之战
1:赤壁之战
2:三足鼎立
--------------
请输入要恢复的存档索引:
1
恢复后的状态
玩家当前完成的历史事件为:赤壁之战
十四、观察者模式
基本介绍
观察者模式:对象之间多对一依赖的一种设计方案,被依赖的对象为 Subject,依赖的对象为 Observer,Subject
通知 Observer 变化,比如这里的奶站是 Subject,是 1 的一方。用户时 Observer,是多的一方。
uml:
Subject:登记注册、移除和通知
addObserver 注 册
deleteObserver 移 除
notifyObservers() 通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送, 看具体需求定
Observer:接收输入
eg.王者荣耀,即将打团,兰陵蓝发出信号,请求集合,其他四个英雄(虞姬、甄姬、项羽、花木兰)立刻回复收到,并且前往支援。
//观察者必须最先创建,它定义了接收消息的方式
public interface Observer{
public void receiveMessage(String message);
}
//再创建主题,它定义了操作观察者的方法
public interface Subject{
public void addObserver(observer.Observer o);
public void deleteObserver(observer.Observer o);
public void notifyObservers();
}
//英雄继承观察者,实现具体接收消息的方法,创建时要将该英雄放入主题中,以便所有英雄统一接收消息
public class HuaMuLan implements Observer {
Subject subject;
//将对象添加到subject的集合中
public HuaMuLan(Subject subject) {
this.subject = subject;
subject.addObserver(this);
}
@Override
public void receiveMessage(String message) {
System.out.println("花木兰收到'"+message+"',正在前往支援");
}
}
public class XiangYu implements Observer {
Subject subject;
//将对象添加到subject的集合中
public XiangYu(Subject subject) {
this.subject = subject;
subject.addObserver(this);
}
@Override
public void receiveMessage(String message) {
System.out.println("项羽收到'"+message+"',正在前往支援");
}
}
//省略剩余两英雄
public class LanLinWang implements Subject {
private String message="";
private List<Observer> observers;
public LanLinWang() {
observers = new ArrayList<>();
}
@Override
public void addObserver(Observer o) {
if (!observers.contains(o)) {
observers.add(o);
}
}
@Override
public void deleteObserver(Observer o) {
if (observers.contains(o)) {
observers.remove(o);
}
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.receiveMessage(message);
}
}
public void publishMessage(String message){
this.message = message;
}
}
//总结:兰陵王要先将队友都添加到观察者集合中,再发送消息,这样队友同一时间都能接收同一消息,再调用各自的方法
public class Client {
public static void main(String[] args) {
LanLinWang lanLinWang = new LanLinWang();
new HuaMuLan(lanLinWang);
new YuJi(lanLinWang);
new ZhenJi(lanLinWang);
new XiangYu(lanLinWang);
String message = "兰陵王请求集合";
System.out.println(message);
lanLinWang.publishMessage(message);
lanLinWang.notifyObservers();
}
}
输出:
兰陵王请求集合
花木兰收到'兰陵王请求集合',正在前往支援
虞姬收到'兰陵王请求集合',正在前往支援
甄姬收到'兰陵王请求集合',正在前往支援
项羽收到'兰陵王请求集合',正在前往支援
十五、访问者模式
- 访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
- 主要将数据结构与数据操作分离,解决 数据结构和操作耦合性问题
- 访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口
- 访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决
uml:
- Visitor 是抽象访问者,为该对象结构中的 ConcreteElement 的每一个类声明一个 visit 操作
- ConcreteVisitor :是一个具体的访问值 实现每个有 Visitor 声明的操作,是每个操作实现的部分.
- ObjectStructure 能枚举它的元素, 可以提供一个高层的接口,用来允许访问者访问元素
- Element 定义一个 accept 方法,接收一个访问者对象
- ConcreteElement 为具体元素,实现了 accept 方法
eg. 一个奶茶店,有两名顾客来买奶茶以及蛋糕,第一名顾客买了12块的奶茶和5块的蛋糕,第二名顾客买了15块的奶茶和8块的蛋糕。收银员根据消费额度,给予折扣,总消费超过20块的打9折,没超过20块的原价销售。使用访问者模式计算出两名顾客最终花的钱数并输出。
public abstract class Customer {
public abstract void buy(Shop s);
}
public class CustomerOne extends Customer {
private Integer milktea;
private Integer cake;
public CustomerOne(Integer milktea, Integer cake) {
this.milktea = milktea;
this.cake = cake;
}
public Integer getMilktea() {
return milktea;
}
public Integer getCake() {
return cake;
}
@Override
public void buy(Shop s) {
s.payOne(this);
}
}
//顾客二省略
public interface Shop {
void payOne(CustomerOne one);
void payTwo(CustomerTwo two);
}
public class SalesMan implements Shop {
@Override
public void payOne(CustomerOne one) {
Integer milktea = one.getMilktea();
Integer cake = one.getCake();
System.out.println("顾客一");
caculate(milktea,cake);
}
@Override
public void payTwo(CustomerTwo two) {
Integer milktea = two.getMilktea();
Integer cake = two.getCake();
System.out.println("顾客二");
caculate(milktea,cake);
}
private void caculate(Integer milktea,Integer cake){
if((milktea + cake) >= 20)
System.out.println("打九折:"+(milktea + cake)*0.9);
else
System.out.println("不打折:"+(milktea + cake));
}
}
public class Client {
public static void main(String[] args) {
Shop salesMan=new SalesMan();
salesMan.payOne(new CustomerOne(12,5));
System.out.println("------------");
salesMan.payOne(new CustomerOne(15,8));
}
}
输出:
顾客一
不打折:17
------------
顾客一
打九折:20.7