软考-23种设计模式

本文详细介绍了设计模式中的简单工厂、工厂方法、抽象工厂、生成器、原型和单例模式,包括它们的概念、应用场景、优缺点和代码示例。通过对这些模式的理解,可以更好地组织和管理代码,提高软件的可维护性和可扩展性。
摘要由CSDN通过智能技术生成

00.简单工厂模式

说明:该工厂类可以根据不同的参数,返回不同的实例对象;被创建的对象通常都有一个共同的抽象父类。工厂模式中创建实例的方法是一个静态方法。(类图如下)

在这里插入图片描述

举个例子:有一家饺子店,店长(工厂)根据客人需求而输入不同的馅料(参数),制作出不同口味的饺子(产品)。

public class m00Factory {
    public static void main(String[] args) {
        try {
            Product pa = Factory.createProduct('A');
            pa.info();
            Product pb = Factory.createProduct('B');
            pb.info();
            Factory.createProduct('C');
        } catch (Exception e) {
            System.err.println("err: 输入参数错误!");
        }
    }
}
// 产品抽象类
abstract class Product{
    public abstract void info();
}
// 产品实现类A
class ProductA extends Product{
    @Override
    public void info() {
        System.out.println("输出产品A");
    }
}
// 产品实现类B
class ProductB extends Product{
    @Override
    public void info() {
        System.out.println("输出产品B");
    }
}
// 简单工厂模式
class Factory{
    public static Product createProduct(char x) throws Exception {
        Product p;
        switch (x){
            case 'A':
                p = new ProductA();break;
            case 'B':
                p = new ProductB();break;
            default:
                throw new Exception();
        }
        return p;
    }
}

【运行结果】

在这里插入图片描述

  • 弊端:每次新增一个新的产品,都要修改工厂的判断条件,使其能创建对应的产品实例。

1.1 工厂方法模式

说明:定义一个用于创建对象的接口,让其子类决定实例化的类。既将实例化延迟到期其子类,这样子在新增一个产品时,只要对应的新增一个实现工厂接口的类即可。(类图如下)

在这里插入图片描述

举个例子:还是这家饺子店,店长(工厂接口)雇佣了若干个店员(工厂实现类),每个店员负责生产一种饺子,客人找到对应的店员下单即可。

public class m01Factory {
    public static void main(String[] args) {
        Product pa = new FactoryA().createProduct();
        pa.info();
        Product pb = new FactoryB().createProduct();
        pb.info();
    }
}
interface Factory{
    public Product createProduct();
}
class FactoryA implements Factory{
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}
class FactoryB implements Factory{
    @Override
    public Product createProduct() {
        return new ProductB();
    }
}
interface Product{
    public void info();
}
class ProductA implements Product{
    @Override
    public void info() {
        System.out.println("输出产品A");
    }
}
class ProductB implements Product{
    @Override
    public void info() {
        System.out.println("输出产品B");
    }
}

【运行结果】

输出产品A
输出产品B

【适用性】

  • 当一个类不知道(不确定)他所必须创建的对象类的时候
  • 当一个类希望有它的子类来具体指定创建的对象的时候

1.2 抽象工厂模式

说明:提供一个创建一系列相关或相互依赖对象的接口(抽象工厂),而无须指定其具体的类。(类图如下)

在这里插入图片描述

例:还是这家饺子店,店长(工厂接口)还是雇佣了若干个店员(工厂实现类),现在每个员工对会制作多种馅料的饺子(多可创建方法)。虽然不同的员工制作一种饺子用的是同一个配方(产品接口),但是各自之间制作出的饺子(对应的产品)各有特色。客户找到自己喜好的员工下单即可。

package model23.m02;

public class m02Factory {
    public static void main(String[] args) {
        System.out.println("店员001-张三");
        Factory f1 = new Factory1();
        f1.createProductA().info();
        f1.createProductB().info();
        System.out.println("店员002-李四");
        Factory f2 = new Factory2();
        f2.createProductA().info();
        f2.createProductB().info();
    }
}
//工厂接口
interface Factory{
    public ProductA createProductA();
    public ProductB createProductB();
}
class Factory1 implements Factory{
    @Override
    public ProductA createProductA() {
        return new ProductA1();
    }
    @Override
    public ProductB createProductB() {
        return new ProductB1();
    }
}
class Factory2 implements Factory{
    @Override
    public ProductA createProductA() {
        return new ProductA2();
    }
    @Override
    public ProductB createProductB() {
        return new ProductB2();
    }
}
//产品A玉米饺子
interface ProductA{
    public void info();
}
class ProductA1 implements ProductA {
    @Override
    public void info() {
        System.out.println("输出张三制作的玉米饺子");
    }
}
class ProductA2 implements ProductA {
    @Override
    public void info() {
        System.out.println("输出李四制作的玉米饺子");
    }
}
//产品B
interface ProductB{
    public void info();
}
class ProductB1 implements ProductB {
    @Override
    public void info() {
        System.out.println("输出张三制作的鲜肉饺子");
    }
}
class ProductB2 implements ProductB {
    @Override
    public void info() {
        System.out.println("输出李四制作的鲜肉饺子");
    }
}

【运行结果】

店员001-张三
输出张三制作的玉米饺子
输出张三制作的鲜肉饺子
店员002-李四
输出李四制作的玉米饺子
输出李四制作的鲜肉饺子

1.3 生成器模式

说明:将一个复杂对象的构建与它的表示分离,使同样的构建过程可以创建出不同的表示。(类图如下)

  • ConcreteBuilder 实现 Builder 的接口,以构造和装配各个部件
  • Director 用来定义 ConcreteBuilder 的执行步骤(实现组件的不同排列)
  • Product 是被构造的复杂对象,最终产品通过ConcreteBuilder 返回给 Director

在这里插入图片描述

举个例子:还是这个饺子店的后厨,厨师(实现类)根据客户的不同的备注需求(导演类),调整食材的咸淡或烹饪顺序,灵活变通生产出满足客户不同需求的产品(产品类)

import java.util.ArrayList;
public class m03Builder {
    public static void main(String[] args) {
        Director director = new Director();
        director.construct();
    }
}
//产品生成
class Product{
    public ArrayList<String> list = new ArrayList<String>();
    //根据接收的参数来添加不同的部件,实现不同的部件有序的排列
    void add(String str){
        list.add(str);
        System.out.println("++ "+str);
    }
    void show(){
        System.out.println("产品部件排列如下:");
        for (String s : list)
            System.out.println(":"+s);
    }
}
//接口-标准
interface Builder{
    public void ability1();  //能力1
    public void ability2();  //能力2
    public Product submit();  //提交项目
}
//实现类-实现操作
class ConcreteBuilder implements Builder{
    Product product = new Product();
    @Override
    public void ability1() {
        product.add("添加部件001");
    }
    @Override
    public void ability2() {
        product.add("添加部件002");
    }
    @Override
    public Product submit() {
        return product;
    }
}
//导演
class Director{
    public void construct(){
        Builder builder = new ConcreteBuilder();
        //导演进行指挥
        builder.ability2();
        builder.ability1();
        //导演收到项目并展示
        builder.submit().show();
    }
}

【运行结果】

++ 添加部件002
++ 添加部件001
产品部件排列如下:
:添加部件002
:添加部件001

【适用性】

  • 当创建创建对象的算法应该独立于该对象的组成部分以及装配顺序(方式)时。
  • 当构造的过程必须允许被构造的对象有不同的表示时。

1.4 原型模式

说明:原型实例指向创建对象种类,通过复制创建新产品

public class m04Prototype {
    public static void main(String[] args) {
        Prototype p = new ConcretePrototype("001","zheng");
        System.out.println(p.hashCode()+" - "+p);
        Prototype clone = (Prototype) p.clone();
        System.out.println(clone.hashCode()+" - "+clone);
    }
}
interface Prototype{
    public Object clone();
}
class ConcretePrototype implements Prototype {
    private String id;
    private String name;
    public ConcretePrototype(){}
    public ConcretePrototype(String id, String name) {
        this.id = id;
        this.name = name;
    }
    @Override
    public String toString() {
        return "{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}';
    }
    @Override
    public Object clone() {
        return new ConcretePrototype(this.id,this.name);
    }
}

【运行结果】

856419764 - {id='001', name='zheng'}
621009875 - {id='001', name='zheng'}
//注1:p实例是父类引用指向子类对象,故p实例不能调用ConcretePrototype中特有的方法
//注2:clone方法返回值类型是Object,也不能调用实现类特有方法(原理同上)

1.5 单例模式

说明:一个类仅有一个实例、一个全局访问点

public class m05Singleton {
    public static void main(String[] args) {
        Singleton s1 = Singleton.getSingleton();
        s1.sets("001","zheng");
        System.out.println("s1"+s1);
        
        Singleton s2 = Singleton.getSingleton();
        s1.sets("002","cheng");
        System.out.println("s1"+s1);
        System.out.println("s2"+s2);
    }
}
class Singleton{
    private String id;
    private String name;
    private Singleton() {}  //将构造方法私有化,使外部无法通过new创建实例
    private static Singleton s = new Singleton(); //只创建一个私有静态对象
    public static Singleton getSingleton(){
        return s;
    }
    public void sets(String id,String name) {
        this.id = id;
        this.name = name;
    }
    @Override
    public String toString() {
        return "{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}';
    }
}

【运行结果】

s1{id='001', name='zheng'}
s1{id='002', name='cheng'}
s2{id='002', name='cheng'}

2.1 适配器模式

说明:将一个类的接口转换成客户希望的接口。(类图如下)

  • Adapter:通过继承得到Target类的方法,然后实例化Adaptee得到其属性和方法
  • 用户实例化Adapter,使用Target原来的接口名称,即可调用Adaptee的方法

在这里插入图片描述

举个例子:用户想给自己的手机充电(use接口),但是现在只有一条TypeC的数据线,用户使用适配器(TypeC转USB)即可充电。

//用户手机是use接口,现只有一条typeC数据线。请制作一个适配器!
public class m06Adapter {
    public static void main(String[] args) {
        System.out.println("用户需要USB输入数据");
        Adapter adapter = new Adapter();
        adapter.function();
    }
}
class USB{
    public void function(){
        System.out.println("++ USB数据输出");
    }
}
class Adapter extends USB{
    private TypeC tc = new TypeC();
    @Override
    public void function() {
        System.out.println("----  适配器  ----");
        tc.function();//接收输入数据并做一定的处理后输出
        super.function();
        System.out.println("-----------------");
    }
}
class TypeC{
    public void function(){
        System.out.println("++TypeC数据输出");
    }
}

【运行结果】

需要USB输入数据
----  适配器  ----
++TypeC数据输出
++转USB数据输出
-----------------

【适用性】

  • 要使用一个已存在的类,但其接口不符合要求(不匹配)。

2.2 桥接模式

说明:将抽象的部分与其实现的部分分离,使他们可以独立地变化。(类图如下)

在这里插入图片描述

举个例子:每种产品都对应有红、蓝两种颜色,若产品与颜色一一对应将会产生很多个类并且不好管理。桥接模式就是将颜色的抽象成一类,并将颜色作为抽象产品的一个对象属性。这样子我们可以将颜色作为一大类单独管理,每当创建一个产品时就设置其颜色即可。

public class m07BridgePattern {
    public static void main(String[] args) {
        Product productA1 = new ProductA();
        productA1.setName("鸿cx01");
        productA1.setColor(new Red());
        Product productA2 = new ProductA();
        productA2.setName("鸿cx02");
        productA2.setColor(new Blue());

        productA1.Operation();
        productA2.Operation();
    }
}
//产品
abstract class Product{
    private String name;
    protected  Color color;  //对象属性

    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public void setColor(Color color) {this.color = color;}

    public abstract void Operation();
}
class ProductA extends Product{
    @Override
    public void Operation() {
        color.OperationImp(this.getName());
    }
}
//产品样式
interface Color{
    public void OperationImp(String name);
}
class Red implements Color{
    @Override
    public void OperationImp(String name) {
        System.out.println("输出产品 名称:"+name+" 样式:红");
    }
}
class Blue implements Color{
    @Override
    public void OperationImp(String name) {
        System.out.println("输出产品 名称:"+name+" 样式:蓝");
    }
}

【运行结果】

输出产品 名称:鸿cx01 样式:红
输出产品 名称:鸿cx02 样式:蓝

【适用性】

  • 不希望在抽象和它的实现部分之间有一个固定的绑定关系。(程序在运行时可被切换)
  • 对一个抽象的实现部分的修改应对客户不产生影响。

2.3 组合模式

说明:将对象合成树型结构以表示“部分-整体”的层次结构。

  • component 为组合中对象声明接口:能实现一些默认行为;声明一些口用于访问和管理子组件。
  • Leaf是没有子组件的叶子节点对象。
  • Composite有子组件的那些组件。

在这里插入图片描述

举个例子:Composite可类比为我们项目中的各个组件、Leaf则是不可再分的每一个对象。组件可以包含其他组件和对象,但Leaf不可存储其他的 leaf 和 composite。

import java.util.ArrayList;
import java.util.List;

public class m08Composite {
    public static void show(Boolean b){
        System.out.println(b?"成功!":"失败!");
    }
    public static void looks(List<Composite> list,String name){
        System.out.print("遍历"+name+"  ");
        for (Composite composite : list) {
            System.out.print(composite.name + " ");
        }
        System.out.println("");
    }
    public static void main(String[] args) {
        Composite root = new Folder("root");
        Composite folder = new Folder("sonFolder");
        Composite file = new File("sonFile");
        show(root.Add(folder));
        show(root.Add(file));
        show(folder.Sub(file));
        show(file.Add(file));
        looks(root.LookOver(),root.name);
    }
}
abstract class Composite{
    protected String name;
    public void printName(){
        System.out.println(name);
    }
    public abstract boolean Add(Composite file);
    public abstract boolean Sub(Composite file);
    public abstract List<Composite> LookOver();
}
class Folder extends Composite{
    private List<Composite> childList = new ArrayList<Composite>();
    public Folder(String name) {
        System.out.println("创建文件夹:"+name);
        this.name=name;
    }
    @Override
    public boolean Add(Composite file) {
        System.out.print(this.name+"执行添加操作:");
        return childList.add(file);
    }
    @Override
    public boolean Sub(Composite file) {
        System.out.print(this.name+"执行删除操作:");
        return childList.remove(file);
    }

    @Override
    public List<Composite> LookOver() {
        return childList;
    }
}
class File extends Composite{
    public File(String name) {
        System.out.println("创建文件:"+name);
        this.name=name;
    }
    @Override
    public boolean Add(Composite file) {
        System.out.print(this.name+"执行添加操作:");
        return false;
    }
    @Override
    public boolean Sub(Composite file) {
        System.out.print(this.name+"执行删除操作:");
        return false;
    }

    @Override
    public List<Composite> LookOver() {
        return null;
    }
}

【运行结果】

创建文件夹:root
创建文件夹:sonFolder
创建文件:sonFile
root执行添加操作:成功!
root执行添加操作:成功!
sonFolder执行删除操作:失败!
sonFile执行添加操作:失败!
遍历root  sonFolder sonFile 

【适用性】

  • 想表示对象的 “部分-整体” 层次结构

2.4 装饰模式

说明:动态的给一个对象添加一些额外的职责。(装饰模式的灵活性更高)

在这里插入图片描述

举个例子:Hero定义了一个英雄类,Decorator是装饰抽象类用于存储一个装饰目标对象和扩展装饰类,两者都继承与Component。其只需要在定义完成英雄类之后,将英雄类对象作为红buff装饰类参数,即可为英雄类对象附加装饰类buff。而当buff时间结束时,也可以很方便的剔除buff效果。

public class m09Decorator {
    public static void main(String[] args) {
        Component hero = new redDecorator(new Hero("亚瑟"));
        hero.operation();
    }
}
abstract class Component{
    protected String name;
    abstract public void operation();
}
class Hero extends Component{
    public Hero(String name) {
        this.name=name;
    }
    @Override
    public void operation() {
        System.out.println(name+"是一个王者英雄!");
    }
}
abstract class Decorator extends Component{
    protected Component obj;
}
//红buff装饰类
class redDecorator extends Decorator{
    public redDecorator(Component obj) {
        this.obj=obj;
    }
    @Override
    public void operation() {
        obj.operation();
        System.out.println("+并且 "+obj.name+"有红buff");
    }
}

【运行结果】

亚瑟是一个王者英雄!
+并且 亚瑟有红buff

【适用性】

  • 可动态的为目标对象添加额外职责,并且添加的职责可方便撤销

2.5 外观模式

说明:为子系统的一组接口提供他有一个一致的界面。

【适用性】

  • 为一个复杂的子系统提供一个简单的接口

2.6 享元模式

说明:运行共享技术有效地支持大量细粒度的对象。但并非所有Flyweight子类都必须被共享,这只是让共享变为可能。

在这里插入图片描述

举个例子:围棋游戏中,我们需要大量相同的黑白棋。我们对于每一个棋子,只需要记住其位置及颜色即可,并不需要大量的重复的对象时,可通过共享对象以减少系统新建对象的开销。

package model23.m11;

public class m11Flyweight {
    public static void main(String[] args) {
        Factory f = new Factory(15);  //创建一个30*30的棋盘
        int mags = 0;
        mags = f.putChess(true,10,12);
        mag(mags);
        mags = f.putChess(false,10,12);
        mag(mags);
    }
    public static void mag(int m){
        switch (m){
            case 1 :System.out.println("该位置有棋子!");break;
            case 2 :System.out.println("棋盘超出范围!");break;
            default:break;
        }
    }
}
class Factory{
    private Flyweight white = new whiteChess();//白棋实例
    private Flyweight black = new blackChess();//黑棋实例
    private int size;
    private int[][] arr;
    public Factory(int size) {
        this.size = size; //初始化,定义棋盘大小
        arr = new int[size][size];
        for (int[] ints : arr) {
            for (int anInt : ints) {
                anInt=0;
            }
        }
    }
    public int putChess(boolean b, int x, int y){
        if(x>size || y>size || x<0 || y<0) return 2;
        if(arr[x][y]!=0) return 1;
        if (b){//true白棋
            arr[x][y]=1;
            System.out.println(white.draw(x,y));
            return 0;
        }
        else{ //false黑棋
            arr[x][y]=2;
            black.draw(x,y);
            return 0;
        }
    }
    public int[][] getChessArr(){
        return arr;
    }
}
abstract class Flyweight{
    protected String color;
    public abstract String draw(int x,int y);
}
//白棋
class whiteChess extends Flyweight{
    public whiteChess() {
        this.color="while";
    }
    @Override
    public String draw(int x, int y) {
        return "白棋  x="+x+"  y="+y;
    }
}
//黑棋
class blackChess extends Flyweight{
    public blackChess() {
        this.color="black";
    }
    @Override
    public String draw(int x, int y) {
        return "黑棋  x="+x+"  y="+y;
    }
}

【运行结果】

白棋  x=10  y=12
该位置有棋子!
    
//该模块实现了一些操作中的错误判断及记录棋子位置而变得复杂。实际上该demo中的所有棋子,仅用了两个对象实例。与单例模式的区别是单例在定义类的时候直接对无参构造私有化,从而只能有一个实例;而享元模式是在创建一个工厂来提前实例化对象,将对象实例封装在方法中给外部调用,实现对象的贡献。

【适用性】

  • 一个应用程序使用了大量的对象,并由于大量的对象造成了巨大的开销

2.7 代理模式

说明:为其他对象提供一种代理以控制对这个对象的访问。(面向切面编程AOP)

注:Proxy不能动态地添加,它强调的是Proxy与它的实体之间的关系。

在这里插入图片描述

举个例子:客户希望租房(subject),房东希望出租(realSubject)。整个时候有一个中介来代理房东出租房子,并帮其签合同和收房租,房东只需要将房子交给中介代理即可。

public class m12Proxy {
    public static void main(String[] args) {
        Proxy proxy = new Proxy(new RealSubject());
        proxy.Request();
    }
}
interface Subject{
    public abstract void Request();//租房请求
}
class Proxy implements Subject{
    private RealSubject real;
    public Proxy(RealSubject real) {
        this.real = real;
    }

    @Override
    public void Request() {     //强化租房请求
        System.out.println("中介代理签合同!");
        real.Request();
        System.out.println("中介代理收房租!");
    }
}
class RealSubject implements Subject {
    @Override
    public void Request(){       //实现租房请求
        System.out.println("房东出租房子");
    }
}

【运行结果】

中介代理签合同!
房东出租房子
中介代理收房租!

3.1 责任链模式

说明:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

在这里插入图片描述

举个例子:学生向辅导员请假只能请一周以内,超过一周的辅导员需要提交院长审批。而对学生而言只需要将请求发给辅导员即可,至于辅导员如何转交院长的过程,学生并不需要关心。

public class m13Chain {
    public static void main(String[] args) {
        Handler c1 = new Concrete1();
        Handler c2 = new Concrete2();
        c1.setNext(c2); //将c2设置为c1的下一级处理对象
        c1.HandlerRequest(12); //12是c1无法处理的,那么c1会将12转发给c2去处理
    }
}
abstract class Handler{
    protected Handler next;  //存储下一级对象
    public void setNext(Handler next) {
        this.next = next;
    }
    public abstract void HandlerRequest(int number);
}
class Concrete1 extends Handler{
    @Override
    public void HandlerRequest(int number) {
        if (number<=7){
            System.out.println("对象1处理该请求!"+number);
        }else if(next!=null){
            next.HandlerRequest(number);
        }else {
            System.out.println("无法处理该请求!");
        }
    }
}
class Concrete2 extends Handler{
    @Override
    public void HandlerRequest(int number) {
        if (number<=15){
            System.out.println("对象2处理该请求!"+number);
        }else if(next!=null){
            next.HandlerRequest(number);
        }else {
            System.out.println("无法处理该请求!");
        }
    }
}

【运行结果】

对象2处理该请求!12 

【适用性】

  • 多个对象处理一个请求,在不明确接受者的情况下,向其中一个对象发送请求。

3.2 命令模式

说明:将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持撤销的操作。

在这里插入图片描述

举个例子:电视机是命令的接收者,通过一定有规定的集成电路板可向电视发送开机命令。但不可能要求用户直接从操作命令,所以这时候还需要将该命令的发送封装到一个开机按钮上去(命令发送者)。

public class m14Command {
    public static void main(String[] args) {
        ConcreteCommand crete = new ConcreteCommand(new Receiver());//命令

        Invoker invoker = new Invoker();
        invoker.setC(crete);
        
        invoker.call();
    }
}
//命令发送者:要求该命令执行这个请求
class Invoker{
    private Command c;
    public void setC(Command c) {
        this.c = c;
    }
    public void call(){
        c.Execute();
    }
}
//执行操作的接口:命令接口
interface Command{
    public void Execute();
}
//将一个接收对象绑定于一个动作
class ConcreteCommand implements Command{
    private Receiver r;
    public ConcreteCommand(Receiver r) {
        this.r = r;
    }
    @Override
    public void Execute() {
        r.opened();//开机动作
    }
}
//命令接收者
class Receiver{
    public void opened(){
        System.out.println("打开电视--开机");
    }
}

【运行结果】

打开电视

【适用性】

  • 抽象出待执行的动作以参数化某对象。
  • 在不同的时刻指定、排列和执行请求。
  • 支持取消操作、修改日志。
  • 有构建的在原语操作上的高层操作构造一个系统

3.3 解释器模式

说明:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

  • Terminal:实现与文法中的终结符相关联的解释操作。
  • Nonterminal:维护Terminal,为文法中的非终结符实现解释操作。
  • Context:解释器之外的一些全局变量。

在这里插入图片描述

import java.util.HashSet;
import java.util.Set;

public class m5 {
    public static void main(String[] args) {
        Context context = new Context();
        context.check("A-开发"); //输入正确!
        context.check("D-开发"); //输入错误!
    } 
}

class Context{
    private String[] regions= {"A","B","C"};
    private String[] persons= {"开发","测试","运维"};
    Expression re,pe,te;

    public Context() {
        re = new Terminalxxx(regions);
        pe = new Terminalxxx(persons);
        te = new Nonterxxx(re,pe);
    }

    public void check(String info){
        boolean interprey = te.Interprey(info);
        if (interprey) System.out.println("输入正确!");
        else System.out.println("输入错误!");
    }
}
interface Expression{
    public boolean Interprey(String info);
}
class Nonterxxx implements Expression{
    Expression re,pe; //维护终结符类型解释器
    public Nonterxxx(Expression re, Expression pe) {
        this.re = re;
        this.pe = pe;
    }
    @Override
    public boolean Interprey(String info) {
        String[] split = info.split("-");
        return re.Interprey(split[0])&&pe.Interprey(split[1]);
    }
}
//初始化时将数组录入集合,调用方法判断参数是否在集合中,返回布尔
class Terminalxxx implements Expression{
    private Set<String> set = new HashSet<>();
    public Terminalxxx(String[] str) {
        for (String s : str) {
            set.add(s);
        }
    }
    @Override
    public boolean Interprey(String info) {
        return set.contains(info);
    }
}

【适用性】

  • 文法简单。
  • 效率不是一个关键的问题。

3.4 迭代器模式

说明:提供一种方法顺序访问一个聚合对象中的各个元素,且不需要暴露该对象的内部表示。

  • ConcreteAggregate(聚合对象):实现创建相应迭代器接口。
  • ConcreteIterator(迭代器对象):遍历时跟踪当前位置。

在这里插入图片描述

import java.util.ArrayList;
import java.util.List;

public class m16 {
    public static void main(String[] args) {
        String[] names = {"数据库概述","数据结构","操作系统","计算机组成原理"};
        String[] prices = {"23.43","43.23","12.40","26.90"};
        bookAggregate books = new bookAggregate(); //book聚合对象
        //创建book对象并存储到聚合对象中
        for (int i = 0; i < 4; i++) {
            boolean add = books.add(new Book(names[i], prices[i]));
            if (!add){
                System.out.println("对象传入集合失败,程序中断!");
                System.exit(0);
            }
        }
        //获取迭代器对象
        Iterator iterator = books.CreateIterator();
        while (iterator.next()){
            Book data = iterator.data();
            System.out.println(data.getName()+"="+data.getPrice());
        }
    }
}
//迭代器
interface Iterator{
    public boolean next();//判断是否还有下一个对象
    public Book data();//获取对象
}
class bookIterator implements Iterator{
    private bookAggregate books;
    private int index=0;
    public bookIterator(bookAggregate books) {
        this.books = books;
    }
    @Override
    public boolean next() {
        return index<books.getSize();
    }
    @Override
    public Book data() {
        Book book = books.getBook(index);
        index++;
        return book;
    }
}
//聚合对象
interface Aggregate{
    public Iterator CreateIterator();
}
class bookAggregate implements Aggregate{
    List<Book> list =  new ArrayList<>();
    public boolean add(Book b){
        return list.add(b);
    }
    public Book getBook(int index){
        return list.get(index);
    }
    public int getSize(){
        return list.size();
    }
    @Override
    public Iterator CreateIterator() {
        return new bookIterator(this);
    }
}
//对象实体
class Book{
    private String name;
    private String price;
    public Book(String name, String price) {
        this.name = name;
        this.price = price;
    }
    public String getName() {
        return name;
    }
    public String getPrice() {
        return price;
    }
}

【运行结果】

数据库概述:23.43
数据结构:43.23
操作系统:12.40
计算机组成原理:26.90

【适用性】

  • 访问一个聚合对象的内容而无需暴露其内部
  • 支持对聚合对象多种遍历方式
  • 为遍历不用的聚合结构提供一个统一的接口

3.5 中介者模式

说明:用一个中介对象来封装一系列的对象交互。中介者使对象不需要显示地相互引用,使得耦合松散,可独立的改变它们之间的交互。

在这里插入图片描述

举个例子:当许多对象需要进行通信时,让对象两两建立联系会产生许多的联系。中介者则是在其中间帮忙传达,在帮助对象与其他对象建立通信。

import java.util.ArrayList;
import java.util.List;

public class m17 {
    public static void main(String[] args) {
        //实例化中介者
        ConcreteMediator mediator = new ConcreteMediator();
        colleague coworka = new colleagueA(mediator);
        colleague coworkb = new colleagueB(mediator);
        mediator.inputs(coworka,coworkb);
        coworka.send("coworka发送信息001",1);
        System.out.println("-------------");
        coworka.send("coworka发送信息002",0);
    }
}
//中介者
abstract class Mediator{
    List<colleague> list = new ArrayList<>();
    //初始化中介者,将有关对象实例存入其中
    public void inputs(colleague...coll) {
        for (colleague colleague : coll) {
            list.add(colleague);
        }
    }
    //消息 , 发送者 , 接收者
    public abstract boolean transmit(String msg,colleague send,int receive);
}
class ConcreteMediator extends Mediator{
    @Override
    public boolean transmit(String msg, colleague send, int receive) {
        //判断发送与接收对象是否为同一个,是则终止
        if (list.get(receive).equals(send))return false;
        //转发信息
        list.get(receive).receive(msg);
        return true;
    }
}
//实体对象
abstract class colleague{
    Mediator mediator;
    public abstract void send(String msg,int end);
    public abstract void receive(String msg);
}
class colleagueA extends colleague{
    public colleagueA(ConcreteMediator mediators) {
        this.mediator=mediators;
    }
    @Override
    public void send(String msg, int end) {
        if (!mediator.transmit(msg,this,end)){
            System.out.println("colleagueA发送失败!");
        }else {
            System.out.println("colleagueA发送成功!");
        }
    }
    @Override
    public void receive(String msg) {
        System.out.println("colleagueA接收信息:"+msg);
    }
}
class colleagueB extends colleague{
    public colleagueB(ConcreteMediator mediators) {
        this.mediator=mediators;
    }
    @Override
    public void send(String msg, int end) {
        if (!mediator.transmit(msg,this,end)){
            System.out.println("colleagueB发送失败!");
        }else {
            System.out.println("colleagueB发送成功!");
        }
    }
    @Override
    public void receive(String msg) {
        System.out.println("colleagueB接收信息:"+msg);
    }
}

【运行结果】

colleagueB接收信息:coworka发送信息001
colleagueA发送成功!
-------------
colleagueA发送失败!

【适用性】

  • 一组对象以良好但复杂的方式进行通信时,产生了混乱的相互依赖(难以维护)。
  • 一个对象引用了其他对象并且直接与这些对象通信,导致难以复用。

3.6 备忘录模式

说明:在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。状态就可以将对象恢复到原先的保存状态。

  • Originator 原发器:创建一个备忘录,用于记录当前状态
  • Memento 备忘录:存储原发器状态
  • Caretaker 管理者:保存备忘录

在这里插入图片描述

举个例子:当我们的程序(原发器)在运行过程中发生中断时(IO中断/缺页中断)。我们需要保存(备忘录)当前程序的状态,先让cpu去处理其他的程序后再放回当前程序,恢复状态后继续执行。当然我们也可能在紧急处理的程序中也发生中断,使用需要一个栈(管理者)来保存多个备忘录。

import java.util.ArrayList;
import java.util.List;

public class m18 {
    public static void main(String[] args) {
        Originator originator = new Originator();
        Memento memento;
        Caretaker caretaker = new Caretaker();

        originator.setState("1024");//设置状态为1024
        memento = originator.createMemento();//创建1024备忘录
        caretaker.addList(memento);//添加备忘录

        originator.setState("2048");
        memento = originator.createMemento();
        caretaker.addList(memento);//添加备忘录

        originator.setState("3072");
        memento = originator.createMemento();
        caretaker.addList(memento);//添加备忘录

        caretaker.showList();//展示备忘录记录
        System.out.println("当前原发器状态:"+originator.getState());
        memento = caretaker.getList(1);
        originator.SetMemento(memento);
        System.out.println("当前原发器状态:"+originator.getState());
    }
}
//原发器
class Originator{
    private String state;
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
    //设置原发器状态
    public void SetMemento(Memento m){
        state=m.getState();
    }
    //创建备忘录
    public Memento createMemento(){
        return new Memento(state);
    }
}
//备忘录
class Memento{
    private String state;
    public Memento(String state) {
        this.state = state;
    }
    public String getState() {
        return state;
    }
}
//管理者
class Caretaker{
    List<Memento> list = new ArrayList<>();
    public boolean addList(Memento m){
        return list.add(m);
    }
    public Memento getList(int index){
        return list.get(index-1);
    }
    public void showList(){
        System.out.println("备忘录记录------");
        int i=0;
        for (Memento memento : list)
            System.out.println("第"+(++i)+"个  "+memento.getState());
    }
}

【运行结果】

备忘录记录------110242204833072
当前原发器状态:3072
当前原发器状态:1024

【适用性】

  • 必须保存一个对象在某时某刻的状态,用于后续恢复状态
  • 不破坏封装性的基础上(不暴露对象细节)暂存状态。

3.7 观察者模式

说明:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所依赖于它的对象都会得到更新。

在这里插入图片描述

举个例子:当粉丝关注了某一个up主,当up主发动态的时候,就会发送一个通知为所有关注他的粉丝。

import java.util.ArrayList;
import java.util.List;

public class m19 {
    public static void main(String[] args) {
        Observer c1 = new ConcreteObserver("xx001");
        Observer c2 = new ConcreteObserver("xx002");
        Observer c3 = new ConcreteObserver("xx003");
        Subject subject = new ConcreteSuject();
        subject.Attach(c1);
        subject.Attach(c2);
        subject.Attach(c3);

        System.out.println("目标状态:"+subject.getState());
        subject.setState("更新中...");//设置状态为更新中
        System.out.println("目标状态:"+subject.getState());
        subject.Detach(c2);         //解除一个观察者c2
        subject.setState("更新完成");//设置状态为更新完成
        System.out.println("目标状态:"+subject.getState());
    }
}
//目标对象
interface Subject{
    public void Attach(Observer o);//添加观察者
    public void Detach(Observer o);//移除观察者
    public void Notify(); //向观察者发送通知
    public void setState(String state);   //设置当前状态
    public String getState(); //获取当前状态
}
class ConcreteSuject implements Subject{
    private String state; //记录当前状态
    //声明一个集合存储多个观察者
    private List<Observer> list = new ArrayList<>();
    public ConcreteSuject() {
        state="初始化状态";
    }
    @Override
    public void Attach(Observer o) {
        list.add(o);
    }
    @Override
    public void Detach(Observer o) {
        list.remove(o);
    }
    @Override
    public void Notify() {
        for (Observer observer : list) {
            observer.update(state);
        }
    }
    @Override
    public void setState(String state) {
        this.state=state;
        Notify();
    }
    @Override
    public String getState() {
        return state;
    }
}
//观察者
interface Observer{
    public void update(String state);//接收更新通知
}
class ConcreteObserver implements Observer{
    private String state;
    private String uid;

    public ConcreteObserver( String uid) {
        this.state = "初始状态";
        this.uid = uid;
    }
    @Override
    public void update(String state) {
        this.state=state;
        System.out.println(uid+"收到更新通知!"+state);
    }
}

【运行结果】

目标状态:初始化状态
xx001收到更新通知!更新中...
xx002收到更新通知!更新中...
xx003收到更新通知!更新中...
目标状态:更新中...
xx001收到更新通知!更新完成
xx003收到更新通知!更新完成
目标状态:更新完成

【适用性】

3.8 状态模式

说明:允许一个对象在其内部状态改变时改变它的行为。

举个例子:一个售卖机(上下文)在运行的过程中,可能出现售空(状态1)和有货(状态2)的状态,需要根据不同情况为该售卖机设置状态

public class m20 {
    public static void main(String[] args) {
        Context context = new Context(0, new StateA());
        context.buy();  //买,失败
        Boolean addc = context.addCount(2);  //补货
        if (addc) System.out.println("补货成功!");
        else System.out.println("补货失败!");
        context.buy();  //买,成功
        context.buy();  //买,成功
        context.buy();  //买,失败
        context.buy();  //买,失败
    }
}
//上下文对象--售卖机
class Context{
    private int count;
    private State state;

    public Context(int count, State state) {
        this.count = count;
        this.state = state;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public void setState(State state) {
        this.state = state;
    }

    //补货
    public Boolean addCount(int count) {
        if (count>0) {
            this.count = count;
            return true;
        }
        return false;
    }
    //买
    public void buy(){
        state.Handle(this);
    }
}
//状态
interface State{
    public void Handle(Context c);
}
class StateA implements State{ //有货
    @Override
    public void Handle(Context c) {
        int count = c.getCount();
        if (count>0){
            System.out.println("出货成功! 存量:"+(count-1));
            c.setCount(count-1);
        }else {
            System.out.println("出货失败!执行退款操作");
            c.setState(new StateB());
        }
    }
}
class StateB implements State{ //无货
    @Override
    public void Handle(Context c) {
        if (c.getCount()>1){
            State stateA = new StateA();
            c.setState(stateA);
            stateA.Handle(c);//转发给有货状态
        }else {
            System.out.println("无货!等待补货..");
        }
    }
}

【运行结果】

出货失败!执行退款操作
补货成功!
出货成功! 存量:1
出货成功! 存量:0
出货失败!执行退款操作
无货!等待补货..

【适用性】

  • 一个对象的行为决定于它的状态,并且必须在运行时根据状态改变它的行为
  • 一个操作中含大量分支条件语句,其这些分支依赖于该对象的状态。

3.9 策略模式

说明:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

举个例子:例如前端开发中,往往开发阶段和生产阶段所使用的不是同一个接口,一个项目(上下文)的开发,往往对应入开发、测试、生产等多套接口(多个策略)

public class m21 {
    public static void main(String[] args) {
        Strategy a = new StrategyA(); //开发
        Strategy b = new StrategyB(); //生产
        Context context;
        context = new Context(a);
        context.operation();
        context = new Context(b);
        context.operation();
    }
}
//上下文
class Context{
    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public void operation(){
        System.out.println("状态模式:"+strategy.function());
    }
}
//策略接口
interface Strategy{
    public String function();
}
//策略A
class StrategyA implements Strategy{
    @Override
    public String function() {
        return "开发模式";
    }
}
//策略B
class StrategyB implements Strategy{
    @Override
    public String function() {
        return "生产模式";
    }
}

【运行结果】

状态模式:开发模式
状态模式:生产模式

3.10 模板方法模式

说明:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。

public class m22 {
    public static void main(String[] args) {
        concrete c = new concrete();
        c.Template();
    }
}
abstract class Abstract{
    //模板方法
    public void Template(){
        System.out.println("模板固定上下文1");
        operation1();
        System.out.println("模板固定上下文2");
        operation2();
    }
    //原语1
    public abstract void operation1();
    //原语2
    public abstract void operation2();
}
class concrete extends Abstract{
    @Override
    public void operation1() {
        System.out.println("对象A实现了原语1");
    }
    @Override
    public void operation2() {
        System.out.println("对象A实现了原语2");
    }
}

【运行结果】

模板固定上下文1
对象A实现了原语1
模板固定上下文2
对象A实现了原语2

【适用性】

  • 一次性实现算法中不变的部分,将需要改变的部分交给子类去实现。
  • 将公共部分提取出来,以免代码重复。(不方便通过传参)

3.11 访问者模式

说明:表示一个作用于某对象结构中的各个元素的操作。它允许在不改变元素的类的前提下定义作用于这些元素的新操作。

举个例子:为图书馆添加一个查询所有书籍及文献页数和的操作,只需要让访问者遍历每一本书并记录求和即可。

package model23.m23;

import java.util.ArrayList;
import java.util.List;

public class m23 {
    public static void main(String[] args) {
        LibraryVisitor visitor = new SumPrintVisitor();
        Library library = new Library();
        library.foreach(visitor);
    }
}
class Library{
    List<LibraryItem> list = new ArrayList<>();
    public Library() {
        Book b1 = new Book("aaa", "001", 268);
        list.add(b1);
        Book b2 = new Book("aaa", "001", 345);
        list.add(b2);
        Article a1 = new Article("asda", "bbb", 80, 5);
        list.add(a1);
    }
    public void foreach(LibraryVisitor visitor){
        for (LibraryItem libraryItem : list) {
            libraryItem.accept(visitor);
        }
        visitor.printSum();
    }

}
interface LibraryVisitor{
    void visit(Book p_book);
    void visit(Article P_article);
    void printSum();
}
class SumPrintVisitor implements LibraryVisitor{
    private int sum = 0;
    @Override
    public void visit(Book P_book) {
        sum+=P_book.getNum();
    }

    @Override
    public void visit(Article P_article) {
        sum+=P_article.getNum();
    }

    @Override
    public void printSum() {
        System.out.println("sum_pape="+sum);
    }
}
abstract class LibraryItem{
    abstract void accept(LibraryVisitor visitor);
}
class Book extends LibraryItem{
    private String itemName;
    private String author;
    private int papes;   //页数

    public Book() {}

    public Book(String itemName, String author, int papes) {
        this.itemName = itemName;
        this.author = author;
        this.papes = papes;
    }
    @Override
    void accept(LibraryVisitor visitor) {
        visitor.visit(this);
    }
    int getNum(){
        return papes;
    }
}
class Article extends LibraryItem{
    private String itemName;
    private String author;
    private int papes;   //页数
    private int start_papes;

    public Article() {}

    public Article(String itemName, String author, int papes, int start_papes) {
        this.itemName = itemName;
        this.author = author;
        this.papes = papes;
        this.start_papes = start_papes;
    }

    @Override
    void accept(LibraryVisitor visitor) {
        visitor.visit(this);
    }
    int getNum(){
        return papes - start_papes;
    }
}
  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值