JAVA设计模式学习

目录:

一、简单工厂模式  二、工厂方法模式  三、抽象工厂模式  四、建造者模式  五、桥接模式
六、组合模式  七、适配器模式  八、装饰者模式  九、状态模式  十、享元模式
十一、命令模式  十二、责任链模式  十三、备忘录模式  十四、观察者模式  十五、访问者模式

一、简单工厂模式

我们在实例化对象的时候通常需要用 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;
	}
}

简单工厂模式实际上就是面向过程=>面向对象的形式,我们把过程封装在工厂容器中,别人看不到,因为做披萨的过程不需要别人知道,别人只管拿到披萨吃就行了。

返回顶部


二、工厂方法模式

工厂方法模式是简单工厂模式的升级版,上面的模式我们会发现一个问题:就是制作披萨的过程是相同的,只是披萨的类型不同,创建多个披萨就要写多个一样的方法,所以需要用到新的方式:创建一个抽象类,抽取共有的方法,所有的披萨继承这个抽象类,制作过程都一样,只需要在其中加入自己独有的方法就行。

  1. 工厂方法模式设计方案:将项目的实例化功能抽象成抽象方法,在不同的子类中具体实现。
  2. 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。

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

返回顶部


三、抽象工厂模式

抽象工厂模式是工厂方法模式的升级版,抽象工厂模式中我们可以定义实现不止一个接口,一个工厂也可以生成不止一个产品类
相当于我要做披萨的同时做面包 ,假设两种用到的原材料都一样,所以我们可以将披萨和面包的原材料提取出来,实现不同的口味就行。

  1. 抽象工厂模式:定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
  2. 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
  3. 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
  4. 将工厂抽象成两层,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:
在这里插入图片描述

  1. Product(产品角色): 一个具体的产品对象。
  2. Builder(抽象建造者): 创建一个 Product 对象的各个部件指定的 接口/抽象类。
  3. ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。
  4. 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());
    }
}

返回顶部


五、桥接模式

现在对不同手机类型的不同品牌实现操作编程(比如:开机、关机、上网,打电话等)
如果我们增加手机的样式,就需要增加各个品牌手机的类,同样如果我们增加一个手机品牌,也要在各个手机样式类下增加。
这违反了单一职责原则,当我们增加手机样式时,要同时增加所有品牌的手机,这样增加了代码维护成本
桥接模式可以解决这一问题。
在这里插入图片描述

  1. Client 类:桥接模式的调用者
  2. 抽象类(Abstraction) :维护了 Implementor / 即它的实现类 ConcreteImplementorA…, 二者是聚合关系, Abstraction充当桥接类
  3. RefinedAbstraction : 是 Abstraction 抽象类的子类
  4. Implementor : 行为实现类的接口
  5. 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());
    }
}

返回顶部


六、组合模式

在这里插入图片描述

  1. Component :这是组合中对象声明接口,在适当情况下,实现所有类共有的接口默认行为,用于访问和管理Component 子部件, Component 可以是抽象类或者接口
  2. Leaf : 在组合中表示叶子节点,叶子节点没有子节点
  3. 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();
    }
}

返回顶部


七、适配器模式

在这里插入图片描述

  1. 适配器模式:将一个类的接口转换成另一种接口.让原本接口不兼容的类可以兼容
  2. 从用户的角度看不到被适配者,是解耦的
  3. 用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
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();
    }
}

返回顶部


八、装饰者模式

在这里插入图片描述

  1. 装饰者模式就像打包一个快递
    主体:比如:陶瓷、衣服 (Component) // 被装饰者
    包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)
  2. Component 主体:比如类似前面的 Drink
  3. ConcreteComponent 和 DecoratorConcreteComponent:具体的主体, 比如前面的各个单品咖啡
  4. 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();
    }
}

返回顶部


九、状态模式

  1. 状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换
  2. 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类

UML图:
在这里插入图片描述

  1. Context 类为环境角色, 用于维护 State 实例,这个实例定义当前状态
  2. State 是抽象状态角色,定义一个接口封装与 Context 的一个特点接口相关行为
  3. 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();
    }
}

返回顶部


十、享元模式

  1. 享元模式(Flyweight Pattern) 也叫 蝇量模式: 运用共享技术有效地支持大量细粒度的对象
  2. 常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
  3. 享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时。不需总是创建新对象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率
  4. 享元模式经典的应用场景就是池技术了,String 常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式

UML图:
在这里插入图片描述

  1. FlyWeight 是抽象的享元角色, 他是产品的抽象类, 同时定义出对象的外部状态和内部状态(后面介绍) 的接口或实现
  2. ConcreteFlyWeight 是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务
  3. UnSharedConcreteFlyWeight 是不可共享的角色,一般不会出现在享元工厂。
  4. 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

返回顶部


十一、命令模式

  1. 命令模式(Command Pattern):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,
    我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计
  2. 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
  3. 在命名模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作。
  4. 通俗易懂的理解:将军发布命令,士兵去执行。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)。
    Invoker 是调用者(将军),Receiver 是被调用者(士兵),MyCommand 是命令,实现了 Command 接口,持有接收对象

uml:
eg.

  1. Invoker 是调用者角色
  2. Command: 是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类
  3. Receiver: 接受者角色,知道如何实施和执行一个请求相关的操作
  4. 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();
    }
}

输出

使用一技能
使用一技能
使用三技能

返回顶部


十二、责任链模式

  1. 职责链模式(Chain of Responsibility Pattern), 又叫 责任链模式,为请求创建了一个接收者对象的链(简单示意图)。这种模式对请求的发送者和接收者进行解耦。
  2. 职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
  3. 这种类型的设计模式属于行为型模式

uml:
在这里插入图片描述

  1. Handler : 抽象的处理者, 定义了一个处理请求的接口, 同时含义另外 Handler
  2. ConcreteHandlerA , B 是具体的处理者, 处理它自己负责的请求, 可以访问它的后继者(即下一个处理者), 如果可以处理当前请求,则处理,否则就将该请求交个 后继者去处理,从而形成一个职责链
  3. 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);
    }
}

输出

启动一级隔离措施,病房隔离
启动二级隔离措施,居家隔离
启动三级隔离措施,方舱医院隔离

返回顶部


十三、备忘录模式

基本介绍

  1. 备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态
  2. 可以这样理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情,或者是记录已经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作
  3. 备忘录模式属于行为型模式

uml:
在这里插入图片描述

  1. originator : 对象(需要保存状态的对象)
  2. Memento : 备忘录对象,负责保存好记录,即 Originator 内部状态
  3. Caretaker: 守护者对象,负责保存多个备忘录对象, 使用集合管理,提高效率
  4. 说明:如果希望保存多个 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();
    }
}

输出:

兰陵王请求集合
花木兰收到'兰陵王请求集合',正在前往支援
虞姬收到'兰陵王请求集合',正在前往支援
甄姬收到'兰陵王请求集合',正在前往支援
项羽收到'兰陵王请求集合',正在前往支援

返回顶部


十五、访问者模式

  1. 访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
  2. 主要将数据结构与数据操作分离,解决 数据结构和操作耦合性问题
  3. 访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口
  4. 访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决

uml:
在这里插入图片描述

  1. Visitor 是抽象访问者,为该对象结构中的 ConcreteElement 的每一个类声明一个 visit 操作
  2. ConcreteVisitor :是一个具体的访问值 实现每个有 Visitor 声明的操作,是每个操作实现的部分.
  3. ObjectStructure 能枚举它的元素, 可以提供一个高层的接口,用来允许访问者访问元素
  4. Element 定义一个 accept 方法,接收一个访问者对象
  5. 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

返回顶部


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值