设计模式JAVA

1 创建型

如何合理的创建对象?

1.1 单例模式

字面意思就是只能创建一个对象实例时使用。

例如,Windows中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。

特点:全局就这一个对象时

懒汉式的实现方式如下:

/**
 * 懒汉单例模式
 */
public class SingleLazyDemo {

    //避免在外部被实例化
    private SingleLazyDemo() {
    }

    private static volatile SingleLazyDemo instance = null;

    //实例化
    public static synchronized SingleLazyDemo getInstance(){
        if(instance == null){
            instance = new SingleLazyDemo();
        }
        return  instance;
    }
    
}

测试效果如下: 

 设计模式JAVA_第1张图片

设计模式JAVA_第2张图片

 饿汉式实现方式如下:

public class SingleHungryDemo {
    //避免在外部被实例化
    private SingleHungryDemo() {
    }

    private static final SingleHungryDemo instance ;
    //一旦加载就创建一个单例
    static {
        instance = new SingleHungryDemo();
    }

    //实例化
    public static synchronized SingleHungryDemo getInstance(){
        return instance;
    }
}

饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的,可以直接用于多线程而不会出现问题。

1.2 原型模式

特点:应用于克隆型对象创建,拷贝原型创建新的对象

原型模式的克隆分为浅克隆和深克隆,Java中的Object类提供了浅克隆的clone()方法,具体原型类只要实现Cloneable接口就可实现对象的浅克隆。

浅克隆的实现方式如下:

import lombok.Data;

@Data
public class PrototypeShallowDemo implements Cloneable{

    private String name;
    private String describe;

    public PrototypeShallowDemo(String name,String describe){
        this.name = name;
        this.describe = describe;
    }

    @Override
    public String toString(){
        return "my name is " + name + ", my info is " + describe;
    }

    protected Object clone() throws CloneNotSupportedException{
        return super.clone();
    }

}

测试效果如下:

设计模式JAVA_第3张图片

浅拷贝的特点:

  • 对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象;
  • 对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,即克隆一份地址。 

深拷贝可以使用对象序列化的方式实现:

@Data
public class PrototypeDeepDemo implements Cloneable, Serializable {
    private String name;
    private PrototypeShallowDemo prototypeShallowDemo;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object object = super.clone();
        PrototypeDeepDemo prototypeDeepDemo = (PrototypeDeepDemo) object;
        prototypeDeepDemo.prototypeShallowDemo = (PrototypeShallowDemo) prototypeShallowDemo.clone();
        return object;
    }
}

1.3 工厂方法模式

特点:创建于使用分离,将创建的对象作为“产品”,把创建产品的对象称为“工厂”。

满足“开闭原则”的前提下,客户随意增删或改变对软件相关对象的使用。

首先实现要生产的产品:

//定一个产品类
public interface Product {
    public String Show();
}

//具体产品1
public class ProductCoffee implements Product{
    @Override
    public String Show() {
        return "this is coffee";
    }
}

//具体产品2
public class ProductPhone implements Product{
    @Override
    public String Show() {
        return "this is phone";
    }
}

然后实现生产工厂:

//定义一个抽象工厂,使用接口interface或者抽象abstract
public interface AbstractFactory {
    public Product CreateProduct();
}

//具体的生产工厂1
public class FactoryCoffee implements AbstractFactory{
    @Override
    public Product CreateProduct() {
        return new ProductCoffee();
    }
}

//具体的生产工厂2
public class FactoryPhone implements AbstractFactory{
    @Override
    public Product CreateProduct() {
        return new ProductPhone();
    }
}

测试实例,调用不同的工厂生产产品:

    @GetMapping("/demo4")
    public String demo4() {
        FactoryCoffee factoryCoffee = new FactoryCoffee();
        Product product = factoryCoffee.CreateProduct();
        FactoryPhone factoryPhone = new FactoryPhone();
        return product.Show() + "______" + factoryPhone.CreateProduct().Show();
    }

设计模式JAVA_第4张图片

 1.4 抽象工厂模式

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

使用抽象工厂模式一般要满足以下条件。

① 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。

② 系统一次只可能消费其中某一族产品,即同族的产品一起使用。

设计模式JAVA_第5张图片

在抽象工厂模式包含如下几个角色:

  • AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
  • ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
  • AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法
  • ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。

1)创建抽象产品和具体产品

//抽象产品1
public abstract class Animal {
    public abstract void getName();
    public abstract void addFood();
    public abstract void getColor();
}

//具体动物1
public class Horse extends Animal{
    @Override
    public void getName() {
        System.out.println("this name is horse");
    }

    @Override
    public void addFood() {
        System.out.println("添加食物");
    }

    @Override
    public void getColor() {
        System.out.println("白色");
    }
}

//具体动物2
public class Cattle extends Animal{
    @Override
    public void getName() {
        System.out.println("this name is cattle");
    }

    @Override
    public void addFood() {
        System.out.println("添加食物");
    }

    @Override
    public void getColor() {
        System.out.println("黑色");
    }
}

//抽象产品2
public abstract class Plant {
    public abstract void getName();
    public abstract void addWater();
}

//具体植物1
public class Fruit extends Plant{
    @Override
    public void getName() {
        System.out.println("这是水果");
    }

    @Override
    public void addWater() {
        System.out.println("浇水");
    }
}

//具体植物2
public class Vegetable extends Plant{
    @Override
    public void getName() {
        System.out.println("这是蔬菜");
    }

    @Override
    public void addWater() {
        System.out.println("浇水");
    }
}

2)抽象工厂

public interface Farm {
    public Plant createPlant();
    public Animal createAnimal();
}

3)具体工厂

//具体工厂1
public class HongXingFarm implements Farm{
    @Override
    public Plant createPlant() {
        System.out.println("蔬菜产生");
        return new Vegetable();
    }

    @Override
    public Animal createAnimal() {
        System.out.println("牛产生");
        return new Cattle();
    }
}

//具体工厂2
public class MingLeFarm implements Farm{
    @Override
    public Plant createPlant() {
        System.out.println("水果产生");
        return new Fruit();
    }

    @Override
    public Animal createAnimal() {
        System.out.println("马产生");
        return new Horse();
    }
}

 4)测试

    @GetMapping("/demo5")
    public void demo5(){
        Farm farm ;
        Animal animal;
        Plant plant;

        farm = new HongXingFarm();
        animal = farm.createAnimal();
        plant = farm.createPlant();

        animal.getName();
        animal.addFood();

        plant.getName();
        plant.addWater();

    }

设计模式JAVA_第6张图片

1.5 建造者模式

背景:在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成。例如,计算机是由CPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、鼠标等部件组装而成的。

它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

建造者模式的主要角色如下:

  • 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个组成部件。
  • 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法getResult()。
  • 具体建造者(Concrete Builder):实现Builder接口,完成复杂产品的各个部件的具体创建方法。
  • 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。

1)设计产品构成

public class Product  {
    private  String partA;
    private  String partB;
    private  String partC;

    public void setPartA(String partA) {
        this.partA = partA;
    }
    public void setPartB(String partB) {
        this.partB = partB;
    }
    public void setPartC(String partC) {
        this.partC = partC;
    }

    public void show()
    {
        System.out.println(partA + partB + partC);
    }
}

2)建造者,负责进行产品的组装

public abstract class Builder {
    //创建产品对象
    protected  Product product=new Product();
    public  abstract void buildPartA();
    public  abstract void buildPartB();
    public  abstract void buildPartC();
    //返回产品对象
    public  Product getResult() {
        return  product;
    }
}

3)具体构造者,实现具体的构建细节

public class HongXIngBuilder extends Builder{
    @Override
    public void buildPartA() {
        product.setPartA("建造PartA");
    }

    @Override
    public void buildPartB() {
        product.setPartB("建造PartB");
    }

    @Override
    public void buildPartC() {
        product.setPartC("建造PartC");
    }
}

4)指挥者,选择具体构建者进行构建

public class Director {

    private  Builder builder;

    public  Director(Builder builder) {
        this.builder=builder;
    }

    //产品构建与组装方法
    public Product construct() {
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
        return builder.getResult();
    }
}

5)使用

    @GetMapping("/demo6")
    public void demo6(){
        //选择HongXIngBuilder
        Builder builder1 = new HongXIngBuilder();
        Director director1 = new Director(builder1);
        Product product1 = director1.construct();
        product1.show();
    }

2 结构型

结构型模式字面意思就是设计程序结构的。

2.1 代理模式

代理就类似于中介,某些情况下不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。

代理模式的主要角色如下:

  • 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  • 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

1)抽象主题

public interface Subject {
    void Request();
    void GetInfo();
}

2)真实主题

public class RealSubject implements Subject{
    @Override
    public void Request() {
        System.out.println("【*】开始访问 ");
    }

    @Override
    public void GetInfo() {
        System.out.println("【info】信息展示 "  + new Date());
    }
}

3)代理

public class Proxy implements Subject{

    private RealSubject realSubject;

    @Override
    public void Request() {
        if(realSubject == null){
            realSubject = new RealSubject();
        }
        preRequest();
        realSubject.Request();
        postRequest();
    }

    @Override
    public void GetInfo() {
        if(realSubject == null){
            realSubject = new RealSubject();
        }
        realSubject.GetInfo();
    }

4)使用

    @GetMapping("/demo7")
    public void demo7(){
        Proxy proxy = new Proxy();
        proxy.GetInfo();
        proxy.Request();
    }

设计模式JAVA_第7张图片

 2.2 适配器模式

开发中两个对象因接口不兼容而不能在一起工作的实例,这时需要第三者进行适配。适配器模式就是将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

适配器模式包含以下主要角色:

  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  • 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
  • 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

1)目标接口

public interface Target {

    void Request();
}

2)适配目标类

public class Adapter {

    public void specificRequest(){
        System.out.println("适配具体请求");
    }

}

 3)适配器

public class TargetAdapter extends Adapter implements Target {
    @Override
    public void Request() {
        specificRequest();
    }
}

4)使用

    @GetMapping("/demo8")
    public void demo8(){
        Target target = new TargetAdapter();
        target.Request();
    }

2.3 桥接模式

将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

桥接(Bridge)模式包含以下主要角色:

  • 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化(Implementor)角色的引用。Abstraction 充当桥接类。
  • 扩展抽象化(Refined Abstraction)角色:是抽象化(Abstraction)角色的子类,实现父类中的业务方法,并通过组合关系调用实现化(Implementor)角色中的业务方法。
  • 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化(Refined Abstraction)角色调用。
  • 具体实现化(Concrete Implementor)角色:给出实现化(Implementor)角色接口的具体实现。

比如4种类型画笔,3种颜色,实现一个画板:

实现方式1: 四种画笔,每种画笔创建三种颜色,共4 *3 = 12 个类

实现方式2:如下,四个形状具体实现类,三个颜色具体实现类,然后定义双继承,也是12个类

设计模式JAVA_第8张图片

实现方式3:如下,用个“桥”去拼接形状和颜色,只有一座“桥”所以类的数量就看上面的4+3=7 

设计模式JAVA_第9张图片

设计模式JAVA_第10张图片

//实现化角色
public interface Impl {
    public void ImplInfo();
}

//具体实现化角色
public class TypeOneImpl implements Impl{
    @Override
    public void ImplInfo() {
        System.out.println("具体实现1");
    }
}

//抽象化角色
public abstract class Abstr {
    protected Impl impl;

    protected Abstr(Impl impl){
        this.impl = impl;
    }

    public abstract void Operation();
}

//扩展抽象化角色
public class AbstrOne extends Abstr{
    public AbstrOne(Impl impl) {
        super(impl);
    }

    @Override
    public void Operation() {
        System.out.println("扩展抽象化访问");
        impl.ImplInfo();
    }

}

//使用
    @GetMapping("/demo9")
    public void demo9(){
        Impl impl = new TypeOneImpl();
        Abstr abstr = new AbstrOne(impl);
        abstr.Operation();
    }

2.4 装饰模式

在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。

装饰模式主要包含以下角色:

  • 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  • 具体装饰(Concrete Decorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

设计模式JAVA_第11张图片

1)抽象构件角色

public interface Shape {
    void draw();
}

2)具体构件角色,未被修饰的原本的内容

public class Rectangle implements Shape{
    @Override
    public void draw() {
        System.out.println("Shape: Rectangle");
    }
}

public class Circle implements Shape{
    @Override
    public void draw() {
        System.out.println("Shape: Circle");
    }
}

3)抽象修饰角色

public abstract class ShapeDecorator implements Shape{

    protected Shape shape;

    public ShapeDecorator(Shape shape){
        this.shape = shape;
    }

    public void draw(){
        shape.draw();
    }
}

4)具体修饰角色,添加修饰类型——颜色修饰

public class RedShapeDecorator extends ShapeDecorator{

    public RedShapeDecorator(Shape shape) {
        super(shape);
    }

    @Override
    public void draw(){
        shape.draw();
        setRedBorder(shape);
    }

    private void setRedBorder(Shape shape){
        System.out.println("Border Color: Red");
    }

}

5)使用

    @GetMapping("/demo10")
    public void demo10(){
        Shape shapeCircle = new Circle();
        ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
        ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());

        shapeCircle.draw();
        System.out.println("-----");
        redCircle.draw();
        redRectangle.draw();
    }

设计模式JAVA_第12张图片

2.5 外观模式

当一个系统的功能越来越强,子系统会越来越多,客户对系统的访问也变得越来越复杂。这时如果系统内部发生改变,客户端也要跟着改变,这违背了“开闭原则”,也违背了“迪米特法则”,所以有必要为多个子系统提供一个统一的接口,从而降低系统的耦合度。

外观模式包含以下主要角色:

  • 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
  • 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。
  • 客户(Client)角色:通过一个外观角色访问各个子系统的功能。

1)外观角色

public interface Shape {
   void draw();
}

2)子系统

public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Rectangle::draw()");
   }
}

public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Square::draw()");
   }
}

3)客户角色

public class ShapeMaker {
   private Shape circle;
   private Shape rectangle;
 
   public ShapeMaker() {
      circle = new Circle();
      rectangle = new Rectangle();
      square = new Square();
   }
 
   public void drawCircle(){
      circle.draw();
   }
   public void drawRectangle(){
      rectangle.draw();
   }

}

4)使用

      ShapeMaker shapeMaker = new ShapeMaker();
 
      shapeMaker.drawCircle();
      shapeMaker.drawRectangle();

2.6 享元模式

在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题。

运用共享技术来有效地支持大量细粒度对象的复用。

享元模式的主要角色有如下:

  • 抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
  • 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
  • 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
  • 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检查系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。

1)非享元

public class UnSharedFlyweight {

    private String info;
    public UnSharedFlyweight(String info){
        this.info = info;
    }

    public String getInfo(){
        return info;
    }

    public void setInfo(String info){
        this.info = info;
    }
}

2)抽象享元

public interface AbstractFlyweight {
    void operation(UnSharedFlyweight unSharedFlyweight);
}

3)具体享元

public class ConcreteFlyweight implements AbstractFlyweight{
    private String key;
    public ConcreteFlyweight(String key){
        this.key = key;
        System.out.println("具体享元" + key + "被创建!");
    }

    @Override
    public void operation(UnSharedFlyweight unSharedFlyweight) {
        System.out.print("具体享元" + key + "被调用, ");
        System.out.println("非享元信息是 " + unSharedFlyweight.getInfo());
    }
}

4)享元工厂

public class FlyweightFactory {
    private HashMap flyweights = new HashMap();

    public AbstractFlyweight getFlyweight(String key){
        AbstractFlyweight flyweight = flyweights.get(key);
        if(flyweight != null){
            System.out.println("具体享元" + key + "已经存在,获取成功!");
        }else{
            flyweight = new ConcreteFlyweight(key);
            flyweights.put(key,flyweight);
        }
        return flyweight;
    }

}

5)使用

    @GetMapping("/demo11")
    public void demo11(){
        FlyweightFactory factory = new FlyweightFactory();
        AbstractFlyweight flyweight1 = factory.getFlyweight("a");
        AbstractFlyweight flyweight2 = factory.getFlyweight("a");
        AbstractFlyweight flyweight3 = factory.getFlyweight("b");
        AbstractFlyweight flyweight4 = factory.getFlyweight("b");
        AbstractFlyweight flyweight5 = factory.getFlyweight("b");

        flyweight1.operation(new UnSharedFlyweight("第一次调用a"));
        flyweight2.operation(new UnSharedFlyweight("第二次调用a"));
        flyweight3.operation(new UnSharedFlyweight("第一次调用b"));
        flyweight4.operation(new UnSharedFlyweight("第二次调用b"));
        flyweight5.operation(new UnSharedFlyweight("第三次调用b"));
    }

设计模式JAVA_第13张图片

实例应用:棋子(ChessPieces)类是抽象享元角色,它包含了一个落子的DownPieces(Graphics g,Point pt)方法;白子(WhitePieces)和黑子(BlackPieces)类是具体享元角色,它实现了落子方法;Point是非享元角色,它指定了落子的位置;WeiqiFactory是享元工厂角色,它通过ArrayList来管理棋子,并且提供了获取白子或者黑子的getChessPieces(String type)方法。 

2.7 组合模式

有时又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。

透明组合模式

//抽象构件
interface Component {
    public void add(Component c);
    public void remove(Component c);
    public Component getChild(int i);
    public void operation();
}

//树叶构件
class Leaf implements Component {
    private String name;
    public Leaf(String name) {
        this.name = name;
    }
    public void add(Component c) {
    }
    public void remove(Component c) {
    }
    public Component getChild(int i) {
        return null;
    }
    public void operation() {
        System.out.println("树叶" + name + ":被访问!");
    }
}

//树枝构件
class Composite implements Component {
    private ArrayList children = new ArrayList();
    public void add(Component c) {
        children.add(c);
    }
    public void remove(Component c) {
        children.remove(c);
    }
    public Component getChild(int i) {
        return children.get(i);
    }
    public void operation() {
        for (Object obj : children) {
            ((Component) obj).operation();
        }
    }
}

//使用
        Component c0 = new Composite();
        Component c1 = new Composite();
        Component leaf1 = new Leaf("1");
        Component leaf2 = new Leaf("2");
        Component leaf3 = new Leaf("3");
        c0.add(leaf1);
        c0.add(c1);
        c1.add(leaf2);
        c1.add(leaf3);
        c0.operation();

3 行为型模式

3.1 模版方法模式

场景:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。又例如例如,简历模板、论文模板、Word中模板文件等。

模版方法模式特点如下:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

模板方法模式包含以下主要角色:

(1)抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下

        ① 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。

        ② 基本方法:是整个算法中的一个步骤,包含以下几种类型。

(2)具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。

//抽象类
public abstract class StencilAbstract {

    public void TemplateMethod() {    //模版方法
        SpecificMethod();
        abstractMethod1();
        abstractMethod2();
    }

    public void SpecificMethod(){    //具体方法
        System.out.println("抽象类中的具体方法被调用");
    }

    public abstract void abstractMethod1();
    public abstract void abstractMethod2();
}

//具体子类
public class ConcreteStencil extends StencilAbstract {
    @Override
    public void abstractMethod1() {
        System.out.println("抽象方法1的实现调用");
    }

    @Override
    public void abstractMethod2() {
        System.out.println("抽象方法2的实现调用");
    }
}

//调用
    @GetMapping("/demo12")
    public void demo12(){
        StencilAbstract sa = new ConcreteStencil();
        sa.TemplateMethod();
    }

3.2 策略模式

当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能。

策略模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。

策略模式的主要角色如下:

  • 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
  • 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

1)抽象策略类

public interface AbstractStrategy {
    public void strategyMethod();
}

2)具体策略类

//具体实现方法2
public class ConcreteStrategyA implements AbstractStrategy{
    @Override
    public void strategyMethod() {
        System.out.println("具体策略A的策略方法被访问!");
    }
}

//具体实现方法1
public class ConcreteStrategyB implements AbstractStrategy{
    @Override
    public void strategyMethod() {
        System.out.println("具体策略B的策略方法被访问!");
    }
}

3)环境类

public class EnvironmentContext {
    private AbstractStrategy strategy;

    public AbstractStrategy getStrategy(){
        return strategy;
    }

    public void setStrategy(AbstractStrategy getStrategy){
        this.strategy = strategy;
    }

    public void strategyMethod(){
        strategy.strategyMethod();
    }
}

4)调用

    @GetMapping("/demo13")
    public void demo13(){
        EnvironmentContext context = new EnvironmentContext();
        AbstractStrategy strategy = new ConcreteStrategyA();
        context.setStrategy(strategy);
        context.strategyMethod();
        System.out.println("_______________");
        strategy = new ConcreteStrategyB();
        context.setStrategy(strategy);
        context.strategyMethod();
    }

3.3 命令模式

背景:在软件开发系统中,常常出现“方法的请求者”与“方法的实现者”之间存在紧密的耦合关系。

命令模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。

命令模式包含以下主要角色:

  • 抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法execute()。
  • 具体命令角色(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
  • 实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
  • 调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。

1)抽象命令类

//抽象命令
public interface Command {
    public abstract void execute();
}

2)具体命令类

public class ConcreteCommand implements Command{

    private Receiver receiver;

    public ConcreteCommand(){
        receiver = new Receiver();
    }
    @Override
    public void execute() {
        receiver.action();
    }
}

3)调用者,发起请求的地方

public class Invoker {
    private Command command;

    public Invoker (Command command){
        this.command = command;
    }

    public void setCommand(Command command){
        this.command = command;
    }

    public void call(){
        System.out.println("调用者治性命令!");
        command.execute();
    }
}

4)接收者,真正实现业务的地方

public class Receiver {
    public void action(){
        System.out.println("接受者的action()方法被调用");
    }
}

5)调用实现

    @GetMapping("/demo14")
    public void demo14(){
        Command cmd = new ConcreteCommand();
        Invoker invoker = new Invoker(cmd);
        invoker.call();
    }

3.4 职责链模式

背景:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如Struts2的拦截器、JSP和Servlet的Filter。

职责链模式:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

职责链模式主要包含以下角色:

  • 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
  • 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

1)抽象处理者

public abstract class RCAbstractHandler {

    private RCAbstractHandler next;

    public void setNext(RCAbstractHandler next){
        this.next = next;
    }

    public RCAbstractHandler getNext(){
        return next;
    }

    //处理请求的方法
    public abstract void handleRequest(String request);

}

2)具体处理者

//具体处理者1
public class ConcreteHandle1 extends RCAbstractHandler{

    @Override
    public void handleRequest(String request) {
        if(request.contains("a")){
            System.out.println("ConcreteHandle1 开始处理");
        }else {
            if(getNext() != null){
                getNext().handleRequest(request);
            }else{
                System.out.println("无处理");
            }
        }
    }

}

//具体处理者2
public class ConcreteHandle2 extends RCAbstractHandler{
    @Override
    public void handleRequest(String request) {
        if(request.contains("b")){
            System.out.println("ConcreteHandle2 开始处理");
        }else {
            if(getNext() != null){
                getNext().handleRequest(request);
            }else{
                System.out.println("无处理");
            }
        }
    }
}

3)调用

    @GetMapping("/demo15")
    public void demo15(@RequestParam("content") String content){
        RCAbstractHandler handler1 = new ConcreteHandle1();
        RCAbstractHandler handler2 = new ConcreteHandle2();

        handler1.setNext(handler2);
        handler1.handleRequest(content);
    }

设计模式JAVA_第14张图片

 3.5 状态模式

背景:应用程序中的有些对象可能会根据不同的情况做出不同的行为,我们把这种对象称为有状态的对象。

状态模式:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。

状态模式包含以下主要角色:

  • 环境(Context)角色:也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
  • 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。
  • 具体状态(Concrete State)角色:实现抽象状态所对应的行为。

1)环境角色

public class StateContext {
    private State state;

    public StateContext(){
        this.state = new ConcreteStateA();
    }

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

    public State getState(){
        return state;
    }

    public void Handle(State state){
        state.Handle(this,state);
    }
}

2)抽象状态

public abstract class State {
    public abstract void Handle(StateContext context,State state);
}

3)具体状态

//具体算法A
public class ConcreteStateA extends State{
    @Override
    public void Handle(StateContext context,State state) {
        System.out.println("this is A");
        context.setState(state);
    }
}

//具体算法B
public class ConcreteStateB extends State{
    @Override
    public void Handle(StateContext context,State state) {
        System.out.println("this is B");
        context.setState(state);
    }
}

4)调用

    @GetMapping("/demo16")
    public void demo16(){
        StateContext context = new StateContext();
        context.Handle(new ConcreteStateA());
        context.Handle(new ConcreteStateA());
        context.Handle(new ConcreteStateB());
    }

设计模式JAVA_第15张图片

3.6 观察者模式

背景:在现实世界中,许多对象并不是独立存在的,其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变

观察者(订阅者)模式:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者模式的主要角色如下:

  • 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
  • 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
  • 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  • 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

1)抽象主题角色

public abstract class ObserverSubject {

    protected List observers=new ArrayList();

    //增加观察者方法
    public void add(Observer observer)
    {
        observers.add(observer);
    }
    //删除观察者方法
    public void remove(Observer observer)
    {
        observers.remove(observer);
    }
    public abstract void notifyObserver(String info); //通知观察者方法
}

2)具体主题

public class ObConcreteSubject extends ObserverSubject {
    @Override
    public void notifyObserver(String info) {
        System.out.println("具体目标发生改变...");
        System.out.println("--------------");

        for(Object obs:observers)
        {
            ((Observer)obs).response(info);
        }
    }
}

3)抽象观察者

public interface Observer {
    void response(String info);
}

4)具体观察者角色

//具体观察者1
public class ObConcreteObserver1 implements Observer{
    @Override
    public void response(String info) {
        System.out.println("具体观察者1作出反应:" + info);
    }
}

//具体观察者2
public class ObConcreteObserver1 implements Observer{
    @Override
    public void response(String info) {
        System.out.println("具体观察者1作出反应:" + info);
    }
}

5)调用

    @GetMapping("/demo17")
    public void demo17(){
        ObserverSubject subject = new ObConcreteSubject();
        Observer observer1 = new ObConcreteObserver1();
        Observer observer2 = new ObConcreteObserver2();

        subject.add(observer1);
        subject.add(observer2);
        subject.notifyObserver("降价了!");
    }

设计模式JAVA_第16张图片

 3.7 中介模式

背景:在现实生活中,常常会出现好多对象之间存在复杂的交互关系,这种交互关系常常是“网状结构”,它要求每个对象都必须知道它需要交互的对象。

中介模式(调停模式):定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。

中介者模式包含以下主要角色:

  • 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
  • 具体中介者(Concrete Mediator)角色:实现中介者接口,定义一个List来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
  • 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
  • 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。

1)中介者

//抽象中介者
public abstract class AbstractMediator {
    public abstract void register(AbstractCollege college);
    public abstract void replay(AbstractCollege cl);
}

//具体中介者
public class ConcreteMediator extends AbstractMediator{

    private List colleges = new ArrayList<>();

    @Override
    public void register(AbstractCollege college) {
        if(!colleges.contains(college)){
            colleges.add(college);
            college.setMediator(this);
        }
    }

    @Override
    public void replay(AbstractCollege cl) {
        for(AbstractCollege college : colleges){
            if(!college.equals(cl)){
                college.receive();
            }
        }
    }
}

2)同事类

//抽象
public abstract class AbstractCollege {
    protected AbstractMediator mediator;

    public void setMediator(AbstractMediator mediator){
        this.mediator = mediator;
    }

    public abstract void receive();
    public abstract void send();
}

//具体1
public class ConcreteCollege1 extends AbstractCollege{
    @Override
    public void receive() {
        System.out.println("college1 收到请求 ");
    }

    @Override
    public void send() {
        System.out.println("college1 发出请求 ");
        mediator.replay(this);//转发
    }
}

//具体2
public class ConcreteCollege2 extends AbstractCollege {
    @Override
    public void receive() {
        System.out.println("college2 收到请求 ");
    }

    @Override
    public void send() {
        System.out.println("college2 发出请求 ");
        mediator.replay(this);
    }
}

3)调用

    @GetMapping("/demo18")
    public void demo18(){
        AbstractMediator mediator = new ConcreteMediator();
        AbstractCollege c1,c2;
        c1 = new ConcreteCollege1();
        c2 = new ConcreteCollege2();
        mediator.register(c1);
        mediator.register(c2);
        c1.send();
        c2.send();
    }

不同对象之间的信息沟通 

设计模式JAVA_第17张图片

3.8 迭代器模式

提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。

迭代器模式主要包含以下角色:

  • 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
  • 具体聚合(Concrete Aggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
  • 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含hasNext()、first()、next()等方法。
  • 具体迭代器(Concrete Iterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

1)抽象聚合

public interface IteratorAggregate {
    public void add(Object obj);
    public void remove(Object obj);
    public Iterator getIterator();
}

2)具体聚合

public class ConcreteAggregate implements IteratorAggregate{
    private List list = new ArrayList<>();
    @Override
    public void add(Object obj) {
        list.add(obj);
    }

    @Override
    public void remove(Object obj) {
        list.remove(obj);
    }

    @Override
    public Iterator getIterator() {
        return new ConcreteIterator(list);
    }
} 
  

3)抽象迭代器

public interface Iterator {
    Object first();
    Object next();
    boolean hashNext();
}

4)具体迭代器


public class ConcreteIterator implements Iterator{

    private List list = new ArrayList<>();
    private int index = 0;

    public ConcreteIterator(List list){
        this.list = list;
    }

    @Override
    public Object first() {
        index = 0;
        Object object = list.get(index);
        return object;
    }

    @Override
    public Object next() {
        Object object = null;
        if(this.hashNext()){
            object = list.get(index++);
        }
        return object;
    }

    @Override
    public boolean hashNext() {
        if(index >= list.size()){
            return false;
        }else {
            return true;
        }
    }
} 
  

5)调用

    @GetMapping("/demo19")
    public void demo19(){
        IteratorAggregate ag = new ConcreteAggregate();
        ag.add("中山大学");
        ag.add("华南理工");
        ag.add("清华大学");
        ag.add("北大大学");

        Iterator it = ag.getIterator();
        while(it.hashNext()){
            Object ob = it.next();
            System.out.println(ob.toString() + "\n");
        }
        Object ob = it.first();
        System.out.println("\nFirst" + ob.toString());
    }

3.9 访问者模式

背景:有些集合对象中存在多种不同的元素,且每种元素也存在多种不同的访问者和处理方式。

访问者模式定义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。 

访问者模式包含以下主要角色:

  • 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作visit(),该操作中的参数类型标识了被访问的具体元素。
  • 具体访问者(Concrete Visitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
  • 抽象元素(Element)角色:声明一个包含接受操作accept()的接口,被接受的访问者对象作为accept()方法的参数。
  • 具体元素(Concrete Element)角色:实现抽象元素角色提供的accept()操作,其方法体通常都是visitor.visit(this),另外具体元素中可能还包含本身业务逻辑的相关操作。
  • 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由List、Set、Map等聚合类实现。

1)抽象访问者

public interface AbstractVisitor {
    void visit(ConcreteElementA element);
    void visit(ConcreteElementB element);
}

2)具体访问者

//具体访问者A
public class ConcreteVisitorA implements AbstractVisitor{
    @Override
    public void visit(ConcreteElementA element) {
        System.out.println("具体A访问者访问:" + element.Operation());
    }

    @Override
    public void visit(ConcreteElementB element) {
        System.out.println("具体A访问者访问:" + element.Operation());
    }
}

//具体访问者B
public class ConcreteVisitorB implements AbstractVisitor{
    @Override
    public void visit(ConcreteElementA element) {
        System.out.println("具体B访问者访问:" + element.Operation());
    }

    @Override
    public void visit(ConcreteElementB element) {
        System.out.println("具体B访问者访问:" + element.Operation());
    }
}

3)抽象元素

public interface Element {
    void accept(AbstractVisitor visitor);
}

4)具体元素

//具体元素A
public class ConcreteElementA implements Element{
    @Override
    public void accept(AbstractVisitor visitor) {
        visitor.visit(this);
    }

    public String Operation(){
        return "具体元素A的操作!";
    }
}

//具体元素B
public class ConcreteElementB implements Element{
    @Override
    public void accept(AbstractVisitor visitor) {
        visitor.visit(this);
    }

    public String Operation(){
        return "具体元素B的操作!";
    }
}

5)对象结构元素

public class ObjectStructure {
    private List list = new ArrayList();

    public void accept(AbstractVisitor visitor){
        Iterator element = list.iterator();
        while(element.hasNext()){
            element.next().accept(visitor);
        }
    }

    public void add(Element element){
        list.add(element);
    }

    public void remove(Element element){
        list.remove(element);
    }
}

6)调用

    @GetMapping("/demo20")
    public void demo20(){
        ObjectStructure obs = new ObjectStructure();
        obs.add(new ConcreteElementA());
        obs.add(new ConcreteElementB());

        AbstractVisitor visitorA = new ConcreteVisitorA();
        obs.accept(visitorA);

        AbstractVisitor visitorB = new ConcreteVisitorB();
        obs.accept(visitorB);
    }

设计模式JAVA_第18张图片

3.10  备忘录模式

备忘录模式(快照模式)能记录一个对象的内部状态,当用户后悔时能撤销当前操作,使数据恢复到它原先的状态。

备忘录模式的主要角色如下:

  • 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
  • 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
  • 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。

1)备忘录

public class Memento {
    private String state;
    public Memento (String state){
        this.state = state;
    }

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

    public String getState(){
        return state;
    }
}

2)发起人

public class Originator {
    private String state;
    public void setState(String state){
        this.state = state;
    }

    public String getState(){
        return state;
    }

    public Memento createMemento(){
        return new Memento(state);
    }

    public void restoreMemento(Memento m){
        this.setState(m.getState());
    }
}

3)管理者

public class Caretaker {
    private Memento memento;

    public void setMemento(Memento m){
        this.memento = m;
    }

    public Memento getMemento(){
        return memento;
    }
}

4)调用

    @GetMapping("/demo21")
    public void demo21(){
        Originator or = new Originator();
        Caretaker cr = new Caretaker();
        or.setState("S0");
        System.out.println("初始状态:" + or.getState());
        cr.setMemento(or.createMemento()); //保存状态
        or.setState("S1");
        System.out.println("新的状态:" + or.getState());
        or.restoreMemento(cr.getMemento()); //恢复状态
        System.out.println("恢复状态:" + or.getState());
    }

设计模式JAVA_第19张图片

你可能感兴趣的:(JavaWeb,设计模式,java)