23种设计模式

根据黑马以及自己的感悟总结而来,如有错误请指正

一、创建者模式(5种)

1.单例模式

确保只有一个实例,并对外提供一个访问点。创建一个单列模式主要有两种思路,饿汉式和懒汉式。

1.1饿汉式

类加载就会导致该单例对象被创建(有两种方式),特点就是随着类的创建而创建,即使你不用它的对象它也存在,一定程度上浪费空间

方式一(静态成员变量)
​
public class Singleton {
 //私有构造方法(确保只有唯一实例)
 private Singleton(){}


 private static Singleton instance = new Singleton();


 //对外提供获取实例的方法
 public static Singleton getInstance (){
     return instance;
 }
}

​
方式二(静态代码块)
public class Singleton {
  //私有构造方法
  private Singleton(){

  }

  private static Singleton instance;

  //在静态代码块中进行赋值
  static {
      instance = new Singleton();
  }

  //对外提供获取该类对象的方法
  public static Singleton getInstance(){
      return instance;
  }
}

1.2 .懒汉式

类加载不会导致该单例对象被创建,而是首次使用该对象被创建

方法一(加锁)
public class Singleton {
  //私有构造方法
  private Singleton(){}

  //声明变量
  private static volatile Singleton instance;  

  //对外提供获取该类对象的方法
  //加锁(synchronized),就保证了多线程时只创建一个对象
  public static synchronized Singleton getInstance(){
      if(instance==null){
          instance = new Singleton();
      }
      return instance;
  }
}
方法二:(双重检查锁)

由于读的操作线程时安全的,方式一的同步代码块性能就很低,所以就有了方式二

​
public class Singleton {
  //私有构造方法
  private Singleton(){

  }

  //声明Singleton类型的变量
  private static volatile Singleton instance;  //只是 声明了对象,没有创建

  //对外提供获取该类对象的方法
  public static Singleton getInstance(){
      //多线程下,读的操作是安全的。所以我们只需要在没有创建的时候加锁创建对象就好了  
      if(instance==null){
          synchronized (Singleton.class){
              instance = new Singleton();
          }
      }
      return instance;
  }
}

​
方式三(静态内部类)
public class Singleton {
  //私有构造方法
  private Singleton(){}

  //定义一个静态内部类
  private static class singletonHolder{
      private static final Singleton INSTANCE = new Singleton();
  }

  //提供获取对象的类
  public static Singleton getInstance(){
      return singletonHolder.INSTANCE;
  }
}


2.工厂模式

当某个类需要一个对象时,往往会直接new出该对象,当多个类都需要这个对象,那么这些类都需要new该对象吗?这显然是不合理的。因为当这个对象的内部需要修改时,那么所有创建了这个对象的类都需要重新修改,这必然违背了软件设计模式的开闭原则。所以我们就需要一个工厂帮我们创建该对象,需要修改时,只需要修改工厂就行了。

2.1 简单工厂模式

解释:用户不再需要去创建宝马车,由工厂进行创建,想要什么车,直接通过工厂创建就可以了。比如想要320i系列车,工厂就创建这个系列的车。

结构:

  • 抽象产品:定义了产品的规范,描述了产品的主要特性和功能

  • 具体产品:实现或继承抽象产品的子类

  • 具体工厂:提供了创建产品的方法,调用者通过该方法来创建产品

实现:

抽象产品:

​//咖啡类(抽象产品)
​
public abstract class Coffee {
   public abstract String getName();

   //加糖
   public void addSugar(){
       System.out.println("加糖");
   }

   //加牛奶
   public void addMile(){
       System.out.println("加糖");
   }
}

具体产品:

//拿铁咖啡类,继承咖啡类(具体产品)
public class LatteCoffee extends Coffee{

   @Override
   public String getName() {
       return "拿铁咖啡";
   }
}
//美式咖啡类(具体产品)
public class Americano extends Coffee{

   @Override
   public String getName() {
       return "美式咖啡";
   }
}

具体产品:

//工厂类(具体工厂)
public class SingleFactory {
   public Coffee createCoffer(String type){
       Coffee coffee = null;
       if("americano".equals(type)){
           coffee = new Americano();
       }else if("latter".equals(type)){
           coffee = new LatteCoffee();
       }

       return coffee;
   }
}

如果有消费者需要咖啡,直接通过咖啡工厂(具体工厂)生产相应的咖啡就行了美式、拿铁(具体产品)。这样我们就不用关心咖啡是怎样生产出来的,只需要关心有什么咖啡产品即可.

缺点:

        增加新的产品时还是需要修改工厂类的代码,违背了开闭原则

2.2 工厂方法模式

工厂方法模式将工厂抽象化,并定义一个创建对象的接口。每增加新产品,只需增加该产品以及对应的具体实现工厂类,由具体工厂类决定要实例化的产品是哪个,将对象的创建与实例化延迟到子类,这样工厂的设计就符合“开闭原则”了,扩展时不必去修改原来的代码。

2.3 抽象工厂模式

抽象工厂模式是为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无需指定索要产品的具体类就可能得到同族的不同等级的产品的模式结构。抽象工厂模式是工厂方法模式的升级版本,工厂方法模式值生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

抽象工厂方法模式的结构

  • 抽象工厂:提供创建产品的接口,调用者通过它的访问具体工厂的工厂方法来创建产品

  • 具体工厂:主要是实现抽象工厂的抽象方法,完成具体的创建

  • 抽象产品:定义了产品的规范,描述了产品的主要特征和功能

  • 具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应

具体实现:

        案例:现咖啡店业务发生改变,不仅要生产咖啡还要生产甜点,如提拉米苏、抹茶慕斯等,要是按照工厂方法模式,需要定义提拉米苏类、抹茶莫斯类、提拉米苏工厂、抹茶慕斯工厂、甜点工厂类,很容易发生类爆炸情况。其中拿铁咖啡、美式咖啡是一个产品等级,都是咖啡;提拉米苏、抹茶慕斯也是一个产品等级;拿铁咖啡喝提拉米苏是同一产品族(也就是属于意大利风味),美式咖啡和抹茶慕斯是同一产品族(也就是属于美式风味)。

抽象产品:

//咖啡
public abstract class Coffee {
   public abstract String getName();

   //加糖
   public void addSugar(){
       System.out.println("加糖");
   }

   //加牛奶
   public void addMile(){
       System.out.println("加糖");
   }
}

抽象工厂:

//甜点抽象类
public abstract class Dessert {
   public abstract void show();
}
//甜点工厂
public interface DessertFactory {
   //生产咖啡的功能
   Coffee createCoffee();

   //生产甜品的功能
   Dessert createDessert();
}

具体产品:

public class AmericanCoffee extends Coffee {
   @Override
   public String getName() {
       return "美式咖啡 ";
   }
}
public class LatteCoffee extends Coffee {

   @Override
   public String getName() {
       return "拿铁咖啡";
   }
}
public class MatchaMouss extends Dessert{
   @Override
   public void show() {
       System.out.println("抹茶慕斯");
   }
}
public class Trimisu extends Dessert{
   @Override
   public void show() {
       System.out.println("提拉米苏");
   }
}

具体工厂:

//意大利甜点工厂,可以生产拿铁咖啡喝提拉米苏
public class ItalyDessertFactory implements DessertFactory{

   @Override
   public Coffee createCoffee() {
       return new LatteCoffee();
   }

   @Override
   public Dessert createDessert() {
       return new Trimisu();
   }
}
//美式甜点工厂,可以生成抹茶慕斯、美式咖啡
public class AmericanDessertFactory implements DessertFactory{
   @Override
   public Coffee createCoffee() {
       return new AmericanCoffee();
   }

   @Override
   public Dessert createDessert() {
       return new MatchaMouss();
   }
}

测试类:

public class test {
   public static void main(String[] args) {
       //创建的是意大利风味甜品工厂对象
       ItalyDessertFactory factory = new ItalyDessertFactory();
       //获取拿铁咖啡和提拉米苏甜品
       Coffee coffee = factory.createCoffee();
       Dessert dessert = factory.createDessert();
       System.out.println(coffee.getName());
       dessert.show();
   }
}


2.4 原型模式

概述:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个原型对象相同的新对象

结构:

  • 抽象原型类:规定了具体原型对象必须实现的clone方法

  • 具体原型类:实现抽象原型类的clone方法,它是可被复制的对象

  • 访问类:使用具体原型类中的clone方法来复制新的对象

实现: 原型模式的克隆分为浅克隆和深克隆

  • 浅克隆:创建一个新的对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址(两个对象里面的属性指向同一块存储空间)

  • 深克隆:创建一个对象,属性中引用的其他对象也会被克隆,不在指向原有对象的地址

这里演示一下浅克隆

//具体类
public class Realizetype implements Cloneable{

    @Override
    public Realizetype clone() throws CloneNotSupportedException {
        //实现具体类的克隆
        return (Realizetype) super.clone();
    }
}
//测试类
public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建一个原型类对象
        Realizetype realizetype = new Realizetype();
        //开始克隆方法进行对象的克隆
        Realizetype clone = realizetype.clone();
        //打印两个对象是否相等
        System.out.println(realizetype==clone);
    }
}

2.4 建造者模式

概述:

        建造者模式(Bulider Pattern)是将一个复杂对象的构建过程与它的实现表示分离,使得同样的构建过程可以创建不同的表示,属于创建型模式。使用创建者模式对于用户而言只需要制定需要建造的类就可以获得对象,建造过程及细节不需要了解。 建造者模式适用于创建对象需要很多步骤,但是步骤的顺序不一定固定。如果一个对象有非常复杂的内部结构(很多属性),可以将复杂对象的创建和使用进行分离。

结构:

  • 抽象建造者类(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的对象部件的创建

  • 具体建造者类(ConcreteBuilder):实现Builder接口,完成复杂产品的各个部件的具体创建方法。在构建过程完成后,提供产品的实例

  • 产品类(product):要创建的复杂对象

  • 指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。

实现:

产品类:

@Data
public class Bike {
    private String frame; //车架

    private String seat; //车座
}

抽象建造者类:

public abstract class Builder {
    //声明Bike类型的变量,并进行赋值
    protected Bike bike = new Bike();

    public abstract void buildFrame();

    public abstract void buildSeat();

    //构建自行车的方法
    public abstract Bike createBike();
}

具体构建者:

//具体的构建者,用来构架摩拜单车对象
public class MobileBuilder extends Builder{
    @Override
    public void buildFrame() {
        bike.setFrame("碳纤维车架");
    }

    @Override
    public void buildSeat() {
        bike.setSeat("真皮车座");
    }

    @Override
    public Bike createBike() {
        return bike;
    }
}
//具体的构建者,ofo单车构建者,用来构建ofo单车
public class OfoBuilder extends Builder{
    @Override
    public void buildFrame() {
        bike.setFrame("铝合金车架");
    }

    @Override
    public void buildSeat() {
        bike.setSeat("橡胶车座");
    }

    @Override
    public Bike createBike() {
        return bike;
    }
}

指挥者类:

public class Director {
    //声明builder类型的变量
    private Builder builder;

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

    //组装自行车的功能
    public Bike Construct(){
        builder.buildFrame();
        builder.buildSeat();
        return builder.createBike();
    }
}

测试类:

public class Client {
    public static void main(String[] args) {
        //创建指挥者类对象
        Director director = new Director(new MobileBuilder());
        //让指挥者指挥组装自行车
        Bike bike = director.Construct();

        System.out.println(bike.getFrame());
        System.out.println(bike.getSeat());
    }
}

建造者模式的优点:
1、封装性好,创建和使用分离;
2、扩展性好,建造类之间独立、一定程度上解耦。
建造者模式的缺点:
1、产生多余的Builder对象;
2、产品内部发生变化,建造者都要修改,成本较大。

二、结构型模式

1. 代理模式

概述:

        由于某些原因需要给某对象提供一个代理以控制该对象的访问。这是访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。java中代理按照代理类生成时机不同又可分为静态代理动态代理。静态代理代理类在编译期就生成,而动态代理类这是在java运行是动态生成。动态代理又有JDK代理和CGLib代理。

结构:

  • 抽象主题类(subject):通过接口或抽象类声明真的主题和代理对象实现的业务方法

  • 真实主题类(Real Subject):实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。

  • 代理类(Proxy):提供了真实主题相同的接口,其内部含有对真实主题的引用,它可以访问,控制或扩展真实主题的功能、

静态代理

抽象主题类:

public interface SellTickets {
  void sell();
}

真实主题类:

public class TrainStation implements SellTickets{
  @Override
  public void sell() {
      System.out.println("火车站卖票");
  }
}

代理类:

public class ProxyPoint implements SellTickets{

  //声明火车战雷对象
  private TrainStation trainStation = new TrainStation();

  @Override
  public void sell() {
      System.out.println("代理点收取一些服务费");
      trainStation.sell();
  }
}

测试类:

public class Client {
  public static void main(String[] args) {
      //创建代售点类对象
      ProxyPoint proxyPoint = new ProxyPoint();
      //调用方法进行买票
      proxyPoint.sell();
  }
}

JDK动态代理

抽象主题类:

public interface SellTickets {
  void sell();
}

真实主题类:

public class TrainStation implements SellTickets{
  @Override
  public void sell() {
      System.out.println("火车站卖票");
  }
}

代理类:

//获取代理对象的工厂类,代理类也实现了对应的接口
public class ProxyFactory {
   //声明目标对象
   private TrainStation trainStation = new TrainStation();

   //获取代理对象的方法
   public SellTickets getProxyObject(){
       //返回代理对象即可
       /**
        * 对象的三个参数
        * ClassLoader loader:类加载器,用于加载代理类,可以通过目标对象获取类加载器
        * Class<?>[] interfaces:代理类实现的接口的字节码对象
        * InvocationHandler h: 代理对象的调用处理程序
        */
       SellTickets proxyObject = (SellTickets) Proxy.newProxyInstance(
               trainStation.getClass().getClassLoader(),
               trainStation.getClass().getInterfaces(),
               new InvocationHandler() {
                   @Override
                   /**
                    * Object proxy: 代理对象和proxyObject对象是同一个对象,在invoke方法中基本
                    * Method method: 对接口中方法进行封装的method对象
                    * Object[] args:调用方法的实际参数
                    * 返回值:方法的返回值
                    */
                   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                       System.out.println("代取点收取一定的服务费用");
                       //执行目标对象的方法
                       Object invoke = method.invoke(trainStation, args);
                       return invoke;
                   }
               }
       );
       return proxyObject;
   }
}

测试类:

public class Client {
   public static void main(String[] args) {
       //获取代理对象
       //1.创建代理共工厂对象
       ProxyFactory factory = new ProxyFactory();
       //2.使用factory对象的方法获取代理对象
       SellTickets proxyObject = factory.getProxyObject();
       //3.调用卖调用的方法
   }
}

CGLIB代理

如果上面的案例没有声明接口,那么JDK代理就用不了了,因为JDK是基于接口代理的。

CGLB是一个功能强大,高新能的代码生成包。

 具体主题类:

public class TrainStation{
   public void sell() {
       System.out.println("火车站卖票");
   }
}

代理类:

//代理对象工厂,用来获取代理对象
public class ProxyFactory implements MethodInterceptor {

   //声明火车站对象、
   private TrainStation trainStation = new TrainStation();

   public TrainStation getProxyObject(){
       //创建Enhancer对象,类似于JDK代理中的Proxy类
       Enhancer enhancer = new Enhancer();
       //设置父类的字节码对象
       enhancer.setSuperclass(TrainStation.class);
       //设置回调函数
       enhancer.setCallbacks(new ProxyFactory[]{this});
       //创建代理对象
       return (TrainStation) enhancer.create();
   }

   @Override
   public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//        System.out.println("方法执行了");
       //要调用目标对象的方法
       System.out.println("代售点收取一定的服务费用(CGLIB代理)");
       return method.invoke(trainStation, objects);
   }
}

测试类:

public class Client {
   public static void main(String[] args) {
       //创建代理工厂对象
       ProxyFactory proxyFactory = new ProxyFactory();
       //获取代理对象
       TrainStation proxyObject = proxyFactory.getProxyObject();
       //调用代理对象中的set方法买票
       proxyObject.sell();  //调佣这个方法就是执行intercept方法
   }
}

2. 适配器模式

定义:

        将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。

结构:

  • 目标类:Target,该角色把其他类转换为我们期望的接口,可以是一个抽象类或接口,也可以是具体类。
  • 被适配者: Adaptee ,原有的接口,也是希望被适配的接口。
  • 适配器: Adapter, 将被适配者和目标抽象类组合到一起的类。

实现:

目标类:

public interface SDCard {
    //从SD卡中读取数据
    String readSD();
    //往SD卡中写数据
    void writeSD(String msg);
}
public class SDCardImpl implements SDCard{
    @Override
    public String readSD() {
        return "SDCard read meg : hello word SD";
    }

    @Override
    public void writeSD(String msg) {
        System.out.println("SDCard write msg : "+msg);
    }
}

适配者类:

public interface TFCard {
    //从TF卡中读取数据
    String readTF();
    //从TF卡中写数据
    void writeTF(String msg);
}
public class TFCardImpl implements TFCard{
    @Override
    public String readTF() {
        return "TFCard read msg : hello word TFCard";
    }

    @Override
    public void writeTF(String msg) {
        System.out.println("TFCard write msg : "+msg);
    }
}

适配器类:

public class SDAdapter extends TFCardImpl implements SDCard{
    @Override
    public String readSD() {
        System.out.println("adapter read tf card");
        return readTF();
    }

    @Override
    public void writeSD(String msg) {
        System.out.println("adapter write tf card");
        writeTF(msg);
    }
}

其他类:

public class Computer {
    //从SD卡中读取数据
    public String readSD(SDCard sdCard){
        if(sdCard==null){
            throw new NullPointerException("sd card is not null");
        }
        return sdCard.readSD();
    }
}

测试类:

public class Client {
    public static void main(String[] args) {
        //创建计算机对象
        Computer computer = new Computer();
        //读取SD卡中的数据
        String msg = computer.readSD(new SDCardImpl());
        System.out.println(msg);

        System.out.println("=================");

        //使用该电脑读取TF卡中的数据
        //定义适配器类
        computer.readSD(new SDAdapter());
    }
}

3. 装饰者模式

概述:

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

相关角色:

  • 抽象构件:可以是接口或者是抽象类,被装饰的最原始的对象。

  • 具体构件:实现抽象构件,通过装饰角色为其添加一些职责

  • 抽象装饰:继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能.

  • 具体装饰:实现抽象装饰的相关方法,并给具体构件对象添加附加责任

实现:

抽象构建:

public abstract class FastFood {

  private float price;    //价格
  private String desc;    //描述

  public abstract float cost();
}

具体构件:

public class FriedRice extends FastFood{
  public FriedRice(){
      super(10,"炒饭");
  }

  @Override
  public float cost() {
      return getPrice();
  }
}
public class FriedNoodles extends FastFood{
  public FriedNoodles(){
      super(12,"炒面");
  }

  @Override
  public float cost() {
      return getPrice();
  }
}

具体装饰者类:

@Data
public abstract class Garnish extends FastFood{
  //声明快餐类的变量
  private FastFood fastFood;

  public Garnish(FastFood fastFood,float price,String desc){
      super(price,desc);
      this.fastFood = fastFood;
  }
}
public class Egg extends Garnish{
  public Egg(FastFood fastFood) {
      super(fastFood, 1, "鸡蛋");
  }

  @Override
  public float cost() {
      return getPrice()+getFastFood().cost();
  }

  @Override
  public String getDesc() {
      return super.getDesc() + getFastFood().getDesc();
  }
}
public class Bacon extends Garnish{
  public Bacon(FastFood fastFood) {
      super(fastFood, 2, "培根");
  }

  @Override
  public float cost() {
      return getPrice()+getFastFood().cost();
  }

  @Override
  public String getDesc() {
      return super.getDesc() + getFastFood().getDesc();
  }
}

测试类:

public class Client {
  public static void main(String[] args) {
      //点一份炒饭
      FastFood food = new FriedRice();
      System.out.println(food.getDesc()+" "+food.cost());

      System.out.println("===========");

      //在上面的炒饭中加一个鸡蛋
      food = new Egg(food);
      System.out.println(food.getDesc()+" "+food.cost());

      System.out.println("===========");

      //再加一个鸡蛋
      food = new Egg(food);
      System.out.println(food.getDesc()+" "+food.cost());

      System.out.println("===========");

      //再加一个培根
      food = new Bacon(food);
      System.out.println(food.getDesc()+" "+food.cost());
  }
}

好处:

  • 饰者模式可以带来比继承更加灵活的扩展功能,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具有良好的扩展性,完美的遵循开闭原则。继承是静态的附加责任,装饰者则是动态的附加责任。

  • 装饰者和被装饰类可以独立发展,不会相互耦合,装饰,模式是继承的一个替代模式。装饰模式可以动态扩展一个实现类的功能

4. 桥接模式

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

结构:

  • 抽象化角色:定义抽象类,并包含一个对实现对象的引用

  • 扩展抽象化角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法

  • 实现化角色:定义实现化据说的接口,供扩展抽象化角色调用

  • 具体实现化角色:给出实现化角色接口的具体实现

案例实现:

抽象化角色:

// 抽象的操作系统类
@AllArgsConstructor
public abstract class OperatingSystem {
    //声明videFile变量
    protected VideoFile videoFile;

    public abstract void play(String fileName);
}]

 扩展抽象话角色:

public class Mac extends OperatingSystem{
    public Mac(VideoFile videoFile) {
        super(videoFile);
    }

    @Override
    public void play(String fileName) {

    }
}
public class Windows extends OperatingSystem{
    public Windows(VideoFile videoFile) {
        super(videoFile);
    }

    @Override
    public void play(String fileName) {
        videoFile.decode(fileName);
    }
}

具体的实现话角色:

public class AviFile implements VideoFile{
    @Override
    public void decode(String fileName) {
        System.out.println("avi视频文件:"+fileName);
    }
}
public class RmvbFile implements VideoFile{
    @Override
    public void decode(String fileName) {
        System.out.println("rmvb视频文件:"+fileName) ;
    }
}
public interface VideoFile {
    //解码功能
    void decode(String fileName);
}

测试类:

public class Client {
    public static void main(String[] args) {
        //创建mac操作系统对象
        OperatingSystem system= new Mac(new AviFile());
        //使用操作系统播放视频文件
        system.play("战狼3");
    }
}

好处:

  • 桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。如:如果现在还有一种视频文件wmv,我们只需要再定义一个类实现VideoFile接口即可,其他类不需要发生变化

  • 实现细节对客户透明

5 外观模式

概述:

        外观模式(Facade Pattern)也称为过程模式,是结构性模式。外观模式为子系统的一组接口提供了一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式可以理解为转换一群接口,客户只要调用这一个接口而不用调用多个接口才能达到目的,也不需关心这个子系统的内部细节。就是解决多个复杂接口带来的使用困难,起到简化用户操作的作用。

结构:

  • 外观角色:为多个子系统对外提供一个共同的接口

  • 子系统角色:实现系统的部分功能,客户可以通过外观角色访问它

实现:

//电灯类
public class Light {
 //开灯
 public void on(){
     System.out.println("打开电灯....");
 }

 //关灯
 public void off(){
     System.out.println("关闭电灯....");
 }
}
public class TV {
 //开启电视机
 public void on(){
     System.out.println("打开电视机....");
 }

 //关闭电视机
 public void off(){
     System.out.println("关闭电视机....");
 }
}
public class AirCondition {
 //打开空调
 public void on(){
     System.out.println("打开空调....");
 }

 //关闭空调
 public void off(){
     System.out.println("关闭空调....");
 }
}

外观类:

public class SmartAppliancesFacade {
 //聚合电灯对象,电视机对象,空调对象
 private Light light;
 private TV tv;
 private AirCondition airCondition;

 public SmartAppliancesFacade(){
     light = new Light();
     tv = new TV();
     airCondition = new AirCondition();
 }

 //通过语音控制
 public void say(String message){
     if(message.contains("打开")){
         on();
     }else if(message.contains("关闭")){
         off();
     }else{
         System.out.println("我还听不懂你说的");
     }
 }

 //一键关闭功能
 private void off() {
     light.off();
     tv.off();
     airCondition.off();
 }

 //一键打开功能
 private void on() {
     light.on();
     tv.on();
     airCondition.on();
 }

}

测试类:

public class Client {
 public static void main(String[] args) {
     //创建自能音响对象
     SmartAppliancesFacade facade = new SmartAppliancesFacade();
     //控制家电
     facade.say("打开家电");

     facade.say("关闭家电");
 }
}

好处:

  • 降低了子系统与客户端之间的耦合度,使得子系统的变化不会影响用它的客户类

  • 对客户屏蔽了子系统组件,减少了客户处理的对象数目,使得子系统使用起来更加容易

缺点:

  • 不符合合开闭原则,修改很麻烦

6. 组合模式

概念:

        又称部分整体模式,是用于把一组相似的对象当做一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分已经整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

结构:

  • 抽象根节点:定义系统各层次对象的共有方法和属性,可以预先定义一些默认行为和属性

  • 树枝节点:定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成了一个树形结构

  • 叶子节点:叶子节点对象,其下午分支,是系统层次遍历的最小单位

实现:

抽象根节点

//菜单组件,属于抽象根节点
public abstract class MenuComponent {
  //菜单组件的名称
  protected String name;
  //菜单组件的层级
  protected int level;

  //添加子菜单
  public void add(MenuComponent menuComponent){
      throw new UnsupportedOperationException();
  }

  //移除子菜单
  public void remove(MenuComponent menuComponent){
      throw new UnsupportedOperationException();
  }

  //获取指定的子菜单
  public MenuComponent getChild(int index){
      throw new UnsupportedOperationException();
  }

  //获取菜单或者菜单项的名称
  public String getName(){
      return name;
  }

  //打印菜单名称(包含子菜单和子菜单项)
  public abstract void print();
}

树枝节点:

public class Menu extends MenuComponent{

  //菜单可以有多个子菜单或者子菜单项
  private List<MenuComponent> menuComponentList = new ArrayList<>();

  //构造方法
  public Menu(String name,int level){
      this.name = name;
      this.level = level;
  }

  @Override
  public void add(MenuComponent menuComponent) {
      menuComponentList.add(menuComponent);
  }

  @Override
  public void remove(MenuComponent menuComponent) {
      menuComponentList.remove(menuComponent);
  }

  @Override
  public MenuComponent getChild(int index) {
      return menuComponentList.get(index);
  }

  @Override
  public void print() {
      //打印菜单名称
      System.out.println(name);
      //打印子菜单或子菜单项名称
      for (MenuComponent menuComponent : menuComponentList) {
          menuComponent.print();
      }
  }
}

叶子节点:

叶子节点public class MenuItem extends MenuComponent {

  public MenuItem(String name,int level){
      this.name = name;
      this.level = level;
  }

  @Override
  public void print() {
      //打印菜单项的名称
      System.out.println(name);
  }
}

测试类:

public class Client {
  public static void main(String[] args) {
      //创建菜单数
      MenuComponent menu1 = new Menu("菜单管理",2);
      menu1.add(new MenuItem("页面访问",3));
      menu1.add(new MenuItem("展开菜单",3));
      menu1.add(new MenuItem("编辑菜单",3));
      menu1.add(new MenuItem("删除菜单",3));
      menu1.add(new MenuItem("新增菜单",3));

      MenuComponent menu2 = new Menu("权限管理",2);
      menu2.add(new MenuItem("页面访问",3));
      menu2.add(new MenuItem("提交保存",3));

      MenuComponent menu3 = new Menu("角色管理",2);
      menu3.add(new MenuItem("页面访问",3));
      menu3.add(new MenuItem("新增角色",3));
      menu3.add(new MenuItem("修改角色",3));
      
      //创建一级菜单
      Menu component = new Menu("系统管理", 1);
      //将二级菜单添加到一级菜单
      component.add(menu1);
      component.add(menu2);
      component.add(menu3);

      //答应菜单名称(若果有子菜单一块打印)
      component.print();
  }
}

7.  享元模式

概述:

        运用共享技术来有效的支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相识对象的开销,从而提高系统资源的利用率

结构:

  • 抽象享元角色(Flyweight):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公 共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法 来设置外部数据(外部状态)。

  • 具体享元(Concrete Flyweight)角色 :它实现了抽象享元类,称为享元对象;在具体享元 类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享 元类提供唯一的享元对象。

  • 非享元(Unsharable Flyweight)角色 :并不是所有的抽象享元类的子类都需要被共享,不 能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。

  • 享元工厂(Flyweight Factory)角色 :负责创建和管理享元角色。当客户对象请求一个享元 对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在 的话,则创建一个新的享元对象。

实现:

抽象享原角色:

public abstract class AbstractBox {
   //获取图形的方法
   public abstract String getShape();
   //显示图形及颜色
   public void display(String color){
       System.out.println("方块形状: "+getShape()+",颜色: "+color);
   }
}

具体享原角色:

public class IBox extends AbstractBox{
   @Override
   public String getShape() {
       return "I";
   }
}
public class LBox extends AbstractBox{
   @Override
   public String getShape() {
       return "L";
   }
}
public class OBox extends AbstractBox{
   @Override
   public String getShape() {
       return "O";
   }
}

享原工厂:

public class BoxFactory {
   private HashMap<String,AbstractBox> map;

   private static BoxFactory boxFactory = new BoxFactory();

   //
   private BoxFactory(){
       map = new HashMap<>();
       map.put("I",new IBox());
       map.put("L",new LBox());
       map.put("O",new OBox());
   }

   public static BoxFactory getInstance(){
       return boxFactory;
   }

   public AbstractBox getShop(String name){
       return map.get(name);
   }
}

测试类:

public class Client {
   public static void main(String[] args) {
       //获取I图形对象
       AbstractBox box1 = BoxFactory.getInstance().getShop("I");
       box1.display("灰色");

       AbstractBox box2 = BoxFactory.getInstance().getShop("O");
       box2.display("白色");

       AbstractBox box3 = BoxFactory.getInstance().getShop("L");
       box3.display("红色");
   }
}

三、行为型模式

1. 模版方法模式

定义:

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

结构:

(1)抽象模板类,负责给出一个算法的轮廓和骨架。

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

  • 基本方法:是算法骨架/流程的某些步骤进行具体实现,包含以下几种类型:抽象方法:在抽象类中声明,由具体子类实现。具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。

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

实现:

 抽象类,定义模版方法和基本方法:

public abstract class AbstractClass {
   //模版方法定义
   public final void cookProcess(){
       pourOil();
       heatOil();
       pourVegetable();
       pourSauce();
       fry();
   }

   public void pourOil(){
       System.out.println("倒油");
   }

   //第二步:热油是一样的,所以直接实现
   public void heatOil(){
       System.out.println("热油");
   }

   //第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)
   public abstract void pourVegetable();

   //第四步,倒调味料是不一样的
   public abstract void pourSauce();

   //第五步:翻抄是一样的,所以直接实现
   public void fry(){
       System.out.println("炒啊炒啊炒");
   }
}

具体子类:

public class ConcreteClass_BaoCai extends AbstractClass{
   @Override
   public void pourVegetable() {
       System.out.println("下锅的蔬菜是包菜");
   }

   @Override
   public void pourSauce() {
       System.out.println("下锅的酱料是辣椒");
   }
}
public class ConcreteClass_CaiXin extends AbstractClass{
   @Override
   public void pourVegetable() {
       System.out.println("下锅的蔬菜是菜心");
   }

   @Override
   public void pourSauce() {
       System.out.println("下锅的酱料是蒜蓉");
   }
}

测试类:

public class Client {
   public static void main(String[] args) {
       //炒包菜
       ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();
       //创建对象
       baoCai.cookProcess();
   }
}

主要优点:

它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
将相同的部分代码提取到抽象父类中,可以提高代码的复用性。
部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
主要缺点:

对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度。
父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍。

2. 策略模式

定义:

        该模式定义了一系列算法,并将每一个算法封装起来,使他们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理

结构:

  • 抽象策略类:这是一个抽象类,通常由一个接口或抽象类实现,此角色给出所有具体策略类所需的接口

  • 具体策略类:实现了抽象策略定义的接口,提供具体的算法实现或行为

  • 环境类:持有一个策略类的应用,最终给客户端调用

实现:

抽象策略类:

public interface Strategy {
    void show();
}

 具体策略类      

public class StrategyA implements Strategy{
    @Override
    public void show() {
        System.out.println("买一送一");
    }
}
public class StrategyB implements Strategy{
    @Override
    public void show() {
        System.out.println("买200减50");
    }
}

环境类:

public class SalesMan {
    //聚合策略类
    private Strategy strategy;

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

    //由销售员展示促销活动给用户
    public void salesMenShow(){
        strategy.show();
    }
}

测试类:

public class Client {
    public static void main(String[] args) {
        //春节来了,使用春节促销活动
        SalesMan salesMan = new SalesMan(new StrategyA());
        //展示促销活动
        salesMan.salesMenShow();

        System.out.println("=======");
        SalesMan salesMan2 = new SalesMan(new StrategyB());
        salesMan2.salesMenShow();
    }
}

3 . 命令模式

定义:

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

结构:

  • 抽象命令(Command):命令是一个抽象接口,定义了执行操作的统一方法。具体的命令类会实现这个接口,并提供执行相应操作的具体逻辑。

  • 具体命令(Concrete Command):具体命令类实现了抽象命令,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。

  • 接收者(Receiver):执行实际命令的类,命令对象会调用接收者的方法来执行请求。

  • 调用者(Invoker):持有命令对象,通常是多个,并通过访问命令对象来执行相关请求,他不直接访问接收者。

实现:

抽象命令类:

public interface Command {
   void execute();
}

具体的命令类:

public class OrderCommand implements Command{
   //持有接受者对象
   private SeniorChef receiver;  //厨师
   private Order order;          //订单

   public OrderCommand(SeniorChef receiver, Order order) {
       this.receiver = receiver;
       this.order = order;
   }

   @Override
   public void execute() {
       System.out.println(order.getDiningTable()+"桌的订单:");
       Map<String, Integer> foodDir = order.getFoodDir();
       //遍历map集合
       Set<String> keys = foodDir.keySet();
       for (String foodName : keys) {
           receiver.makeFood(foodName,foodDir.get(foodName));
       }

       System.out.println(order.getDiningTable()+"桌的饭准备完毕");
   }
}

订单类:

public class Order {
   //餐桌号码
   private int diningTable;

   //所下的餐品的及份数
   private Map<String,Integer> foodDir = new HashMap<>();

   public int getDiningTable() {
       return diningTable;
   }

   public void setDiningTable(int diningTable) {
       this.diningTable = diningTable;
   }

   public Map<String, Integer> getFoodDir() {
       return foodDir;
   }

   public void setFood(String name,int num) {
       foodDir.put(name,num);
   }
}

请求者角色:

public class SeniorChef {
   public void makeFood(String name,int num){
       System.out.println(num+"份"+name);
   }
}
public class Waiter {
   //持有多个命令对象
   private List<Command> commands = new ArrayList<>();

   public void setCommand(Command command){
       //将cmd对象存储到list集合中
       commands.add(command);
   }

   //发起命令功能 喊订单来了
   public void orderUp(){
       System.out.println("服务员:大厨,订单来了。。。");
       for (Command command : commands) {
           if(command != null){
               command.execute();
           }
       }
   }
}

测试类:

public class Client {
   public static void main(String[] args) {
       //创建第一个订单对象
       Order order1 = new Order();
       order1.setDiningTable(1);
       order1.setFood("西红柿鸡蛋面",1);
       order1.setFood("小杯可乐",2);

       //创建第二个订单对象
       Order order2 = new Order();
       order2.setDiningTable(2);
       order2.setFood("尖椒肉丝盖饭",1);
       order2.setFood("小杯雪碧",2);

       //创建厨师对象
       SeniorChef receiver = new SeniorChef();
       //创建命令对象
       OrderCommand orderCommand1 = new OrderCommand(receiver,order1);
       OrderCommand orderCommand2 = new OrderCommand(receiver,order2);

       //创建调用者(服务员对象)
       Waiter waiter = new Waiter();
       waiter.setCommand(orderCommand1);
       waiter.setCommand(orderCommand2);

       //让服务员发起命令
       waiter.orderUp();
   }
}

4 责任链模式

定义:

        避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止

结构:

  • 抽象处理者角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接

  • 具体处理者:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则该请求转给他的后继者

  • 客户类:创建处理链,并向链头的具体处理者对象提交请求

实现:

public class LeaveRequest {
   //姓名
   private String name;
   //请假天数
   private int num;
   //请假内容
   private String content;

   public LeaveRequest(String name, int num, String content) {
       this.name = name;
       this.num = num;
       this.content = content;
   }

   public String getName() {
       return name;
   }

   public int getNum() {
       return num;
   }

   public String getContent() {
       return content;
   }
}

 抽象处理者:

public abstract class Handler {
   protected final static int NUM_ONE = 1;
   protected final static int NUM_THREE = 3;
   protected final static int NUM_SEVEN = 7;

   //该领导处理的请假天数区间
   private int numStart;
   private int numEnd;

   //声明后续者(声明上级领导)
   private Handler nextHandler;

   public Handler(int numStart){
       this.numStart = numStart;
   }

   public Handler(int numStart, int numEnd) {
       this.numStart = numStart;
       this.numEnd = numEnd;
   }

   //设置上级领导对象
   public void setNextHandler(Handler nextHandler) {
       this.nextHandler = nextHandler;
   }

   //各级领导处理请假条的方法
   protected abstract void handleLeave(LeaveRequest leave);

   //提交请假条
   public final void submit(LeaveRequest leave){
       //该领导进行审批
       this.handleLeave(leave);
       if(this.nextHandler != null && leave.getNum() > this.numEnd){
           //提交给上级领导审批
           this.nextHandler.submit(leave);
       }else{
           System.out.println("流程结束!");
       }
   }
}

具体的处理者:

public class GroupLeader extends Handler{

   public GroupLeader(){
       super(0,Handler.NUM_ONE);
   }

   @Override
   protected void handleLeave(LeaveRequest leave) {
       System.out.println(leave.getName() + "请假" +leave.getNum() + "天,"+leave.getContent() + "。");
       System.out.println("小组长审批:同意");
   }
}
public class GeneralManager extends Handler{

   public GeneralManager(){
       super(Handler.NUM_THREE,Handler.NUM_SEVEN);
   }

   @Override
   protected void handleLeave(LeaveRequest leave) {
       System.out.println(leave.getName() + "请假" +leave.getNum() + "天,"+leave.getContent() + "。");
       System.out.println("总经理审批:同意");
   }
}
public class Manager extends Handler{

   public Manager(){
       super(Handler.NUM_ONE,Handler.NUM_THREE);
   }

   @Override
   protected void handleLeave(LeaveRequest leave) {
       System.out.println(leave.getName() + "请假" +leave.getNum() + "天,"+leave.getContent() + "。");
       System.out.println("部门经理审批:同意");
   }
}

测试类:

public class Client {
   public static void main(String[] args) {
       //创建一个请假条对象
       LeaveRequest leaveRequest = new LeaveRequest("小明", 1, "身体不适");

       //创建各级领导对象
       GroupLeader groupLeader = new GroupLeader();
       Manager manager = new Manager();
       GeneralManager generalManager = new GeneralManager();

       //设置处理者
       generalManager.setNextHandler(manager);
       manager.setNextHandler(generalManager);

       //小明提交请假申请
       groupLeader.submit(leaveRequest);
   }
}

5. 状态模式

定义:

        状态模式是一种行为型设计模式。它允许对象在内部状态发生改变时改变它的行为,简单地讲就是,一个拥有状态的context对象,在不同状态下,其行为会发生改变。

构成:

  • 上下文(Context):定义客户端需要的接口,并且负责具体状态的切换。

  • 抽象状态(Abstract State):抽象状态类是所有具体状态类的基类或接口。负责定义该状态下的行为,可以一个或多个。

  • 具体状态(Concrete State):具体状态类实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。

实现:

抽象状态类:

public abstract class LiftState {
   //声明环境角色类变量
   protected Context context;

   public void setContext(Context context) {
       this.context = context;
   }

   //电梯开启操作
   public abstract void open();
   //电梯关闭操作
   public abstract void close();
   //电梯运行操作
   public abstract void run();
   //电梯停止操作
   public abstract void stop();
}
public class Context {
   //定义对应状态对象的常量
   public final static OpeningState OPENING_STATE = new OpeningState();
   public final static ClosingState CLOSING_STATE = new ClosingState();
   public final static RunningState RUNNING_STATE = new RunningState();
   public final static StoppingState STOPPING_STATE = new StoppingState();

   //定义一个当前电梯状态变量
   private LiftState liftState;

   public LiftState getLiftState() {
       return liftState;
   }

   //设置当前状态对象
   public void setLiftState(LiftState liftState) {
       this.liftState = liftState;
       //设置当前状态对象中的Context对象
       this.liftState.setContext(this);
   }

   public void open(){
       this.liftState.open();
   }

   public void close(){
       this.liftState.close();
   }

   public void run(){
       this.liftState.run();
   }

   public void stop(){
       this.liftState.stop();
   }
}

状态类:

public class ClosingState extends LiftState{
   @Override
   public void open() {

   }

   @Override
   public void close() {

   }

   @Override
   public void run() {

   }

   @Override
   public void stop() {

   }
}
public class OpeningState extends LiftState{
   //当前状态要执行的方法
   @Override
   public void open() {
       System.out.println("电梯开启。。。");
   }

   @Override
   public void close() {
       //修改状态
       context.setLiftState(Context.CLOSING_STATE);
       //调用当前状态中context中的close方法
       context.close();
   }

   @Override
   public void run() {
       //什么都不做
   }

   @Override
   public void stop() {
       //什么都不做
   }
}
//电梯运行状态类(这个类没有补充完)
public class RunningState extends LiftState{
   @Override
   public void open() {

   }

   @Override
   public void close() {

   }

   @Override
   public void run() {

   }

   @Override
   public void stop() {

   }
}
public class StoppingState extends LiftState{
   @Override
   public void open() {

   }

   @Override
   public void close() {

   }

   @Override
   public void run() {

   }

   @Override
   public void stop() {

   }
}

6 观察者模式

定义:

        又被称为发布-订阅模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化是,会通知所有的观察者对象,是他们能够自动更新自己。

 结构:

  • 抽象被观察者(Subject):定义了一个接口,包含了注册观察者、删除观察者、通知观察者等方法。

  • 具体被观察者(ConcreteSubject):实现了抽象被观察者接口,维护了一个观察者列表,并在状态发生改变时通知所有注册的观察者。

  • 抽象观察者(Observer):定义了一个接口,包含了更新状态的方法。

  • 具体观察者(ConcreteObserver):实现了抽象观察者接口,存储了需要观察的被观察者对象,并在被观察者状态发生改变时进行相应的处理。

实现:

抽象观察着类

public interface Observer {
   void update(String observer);
}

抽象主题角色类

public interface Subject {
   //添加订阅者(添加观察者对象)
   void attach(Observer observer);

   //删除订阅者
   void detach(Observer observer);

   //通知订阅者更新信息
   void notify(String message);
}

具体主题角色类:

public class SubscriptionSubject implements Subject{

   //定义一个集合,用来存储多个观察者对象
   private List<Observer> weiXinUserList = new ArrayList<>();

   @Override
   public void attach(Observer observer) {
       weiXinUserList.add(observer);
   }

   @Override
   public void detach(Observer observer) {
       weiXinUserList.remove(observer);
   }

   @Override
   public void notify(String message) {
       //遍历集合
       for (Observer observer : weiXinUserList) {
           //调用观察着对象中的update方法
           observer.update(message);
       }
   }
}

具体的观察者角色类

public class WeiXinUser implements Observer{

   private String name;

   public WeiXinUser(String name) {
       this.name = name;
   }

   @Override
   public void update(String message) {
       System.out.println(name+"-"+message);
   }
}
public class Client {
   public static void main(String[] args) {
       //创建公众号对象
       SubscriptionSubject subject = new SubscriptionSubject();

       //订阅公众号
       subject.attach(new WeiXinUser("孙悟空"));
       subject.attach(new WeiXinUser("猪悟能"));
       subject.attach(new WeiXinUser("沙悟净"));

       //公众号更新,发出消息给订阅者(观察着对象)
       subject.notify("愚者向你问好");
   }
}

7. 中介者模式

定义:

        又叫调停模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立的改变他们之间的交互

结构:

  • 抽象中介者(Mediator):用于协调各个同事对象之间交互的通用接口,如接收和发送消息等。

  • 具体中介者(Concrete Mediator):实现抽象中介者接口,定义一个List来管理同时对象,协调各个同事对象之间的交互,依赖于同事角色。

  • 抽象观察者(Observer):定义了一个接口,包含了更新状态的方法。

  • 抽象同事类(Colleague):保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。

  • 具体同事类(Concrete Colleague):实现抽象同事类接口,当需要与其他同事对象交互时,由中介者对象负责后续的交互,简单地说就是维护和中介者对象的通信。

实现:

public class Person {
   protected String name;
   protected Mediator mediator;

   public Person(String name, Mediator mediator) {
       this.name = name;
       this.mediator = mediator;
   }
}

具体的同事角色类

public class HouseOwner extends Person{
   public HouseOwner(String name, Mediator mediator) {
       super(name, mediator);
   }

   //和中介联系(沟通)
   public void constact(String message){
       mediator.constact(message,this);
   }

   //获取信息
   public void getMessage(String message){
       System.out.println("房主"+name+"获取到的信息是"+message);
   }
}

抽象中介者类

public abstract class Mediator {
   public abstract void constact(String message,Person person);
}

具体的中介者角色类

public class MediatorStructure extends Mediator{

   //聚合房主和租房者对象
   private HouseOwner houseOwner;
   private Tenant tenant;

   public HouseOwner getHouseOwner() {
       return houseOwner;
   }

   public void setHouseOwner(HouseOwner houseOwner) {
       this.houseOwner = houseOwner;
   }

   public Tenant getTenant() {
       return tenant;
   }

   public void setTenant(Tenant tenant) {
       this.tenant = tenant;
   }

   @Override
   public void constact(String message, Person person) {
       if(person==houseOwner){
           //如果是房东
           tenant.constact(message);
       }else{
           //租房者
           houseOwner.getMessage(message);
       }
   }
}

测试类:

public class Client {
   public static void main(String[] args) {
       //创建中介者对象
       MediatorStructure mediator = new MediatorStructure();

       //创建租房者对象
       Tenant tenant = new Tenant("李四",mediator);
       //创建房主对象
       HouseOwner houseOwner = new HouseOwner("张三", mediator);

       //中介者知道具体的房东和租房者
       mediator.setTenant(tenant);
       mediator.setHouseOwner(houseOwner);

       tenant.constact("我要租三室的房子!!!");
       houseOwner.constact("我这里有三室的房子,你要租吗?");
   }
}

8. 迭代器模式

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

结构:

  • 抽象迭代器(Iterator):定义了遍历聚合对象所需的方法,包括hashNext()和next()方法等,用于遍历聚合对象中的元素。

  • 具体迭代器(Concrete Iterator):它是实现迭代器接口的具体实现类,负责具体的遍历逻辑。它保存了当前遍历的位置信息,并可以根据需要向前或向后遍历集合元素。

  • 抽象聚合器(Aggregate): 一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等。

  • 具体聚合器(ConcreteAggregate):就是抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等。

实现:

public class Student {
   private String name;
   private String number;

   public Student() {
   }

   public Student(String name, String number) {
       this.name = name;
       this.number = number;
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public String getNumber() {
       return number;
   }

   public void setNumber(String number) {
       this.number = number;
   }

   @Override
   public String toString() {
       return "Student{" +
               "name='" + name + '\'' +
               ", number='" + number + '\'' +
               '}';
   }
}

抽象聚合角色接口

public interface StudentAggregate {
   //添加学生功能
   void addStudent(Student stu);
   //删除学生功能
   void removeStudent(Student stu);
   //获取迭代器对象功能
   StudentIterator getStudentIterator();
}

具体的迭代器角色类

public class StudentAggregateImpl implements StudentAggregate{
   private List<Student> list = new ArrayList<>();

   @Override
   public void addStudent(Student stu) {
       list.add(stu);
   }

   @Override
   public void removeStudent(Student stu) {
       list.remove(stu);
   }

   //获取迭代器对象
   @Override
   public StudentIterator getStudentIterator() {
       return new StudentIteratorImpl(list);
   }
}
public interface StudentIterator {
   //判断是否还有元素
   boolean hasNext();

   //获取下一个元素
   Student next();
}

具体迭代器角色类

public class StudentIteratorImpl implements StudentIterator{

   private List<Student> list;
   private int position = 0; //用来记录遍历时的位置

   public StudentIteratorImpl(List<Student> list) {
       this.list = list;
   }

   @Override
   public boolean hasNext() {
       return position < list.size();
   }

   @Override
   public Student next() {
       //从集合中获取指定位置的元素
       Student student = list.get(position);
       position++;
       return student;
   }
}

测试类:

public class Client {
   public static void main(String[] args) {
       //创建聚合对象
       StudentAggregateImpl aggregate = new StudentAggregateImpl();
       //添加元素
       aggregate.addStudent(new Student("张三","001"));
       aggregate.addStudent(new Student("李四","002"));
       aggregate.addStudent(new Student("王五","003"));

       //遍历聚合对象
       //1.获取迭代器对象
       StudentIterator iterator = aggregate.getStudentIterator();
       //2.遍历
       while (iterator.hasNext()){
           //3.获取元素
           Student student = iterator.next();
           System.out.println(student.toString());
       }
   }
}

9 . 访问者模式

定义:

        封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这写元素的新的操作

构成:

  • 抽象访问者(Visitor)角色:定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素,它的方法个数理论上来讲与元素类个数(Element的实现类个数)是一样的,从这点不难看出,访问者模式要求元素类的个数不能改变。

  • 具体访问者(ConcreteVisitor)角色: 具体访问者实现了每个由抽象访问者声明的操作,每一个操作用于访问对象结构中一种类型的元素。

  • 抽象元素(Element)角色:定义了一个接受访问者的方法(accept),其意义是指,每一个元素都要可以被访问者访问。

  • 具体元素(ConcreteElement)角色: 提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。

  • 对象结构(ObjectStructure)角色: 对象结构是一个元素的集合,它用于存放元素对象,并且提供了遍历其内部元素的方法。它可以结合组合模式来实现,也可以是一个简单的集合对象,如一个List对象或一个Set对象。

实现:

抽象访问者:

public interface Animal {
   //接收访问者访问的功能
   void accept(Person person);
}

具体元素角色类

public class Cat implements Animal{

   @Override
   public void accept(Person person) {
       person.feed(this);//访问者给宠物猫喂食
       System.out.println("好好吃,喵喵喵");
   }
}
public class Dog implements Animal{
   @Override
   public void accept(Person person) {
       person.feed(this);//访问者给宠物狗喂食
       System.out.println("好好吃,汪汪汪");
   }
}

抽象访问者角色类

public interface Person {
   //喂食宠物猫
   void feed(Cat cat);
   //喂食宠物狗
   void feed(Dog dog);
}

    具体的访问者角色类

public class Someone implements Person{
   @Override
   public void feed(Cat cat) {
       System.out.println("其他人喂食猫");
   }

   @Override
   public void feed(Dog dog) {
       System.out.println("其他人喂食狗");
   }
}

具体的访问者角色类

public class Owner implements Person{
   @Override
   public void feed(Cat cat) {
       System.out.println("主人喂食猫");
   }

   @Override
   public void feed(Dog dog) {
       System.out.println("主人喂食狗");
   }
}

对象结构类

public class Home {
   //声明一个集合对象,用来存储元素对象
   private List<Animal> nodeList = new ArrayList<>();

   //添加元素功能
   public void add(Animal animal){
       nodeList.add(animal);
   }

   public void action(Person person){
       //遍历结合,获取每一个元素,让访问者访问每一个元素
       for (Animal animal : nodeList) {
           animal.accept(person);
       }
   }
}

测试类:

public class Client {
   public static void main(String[] args) {
       //创建home对象
       Home home = new Home();
       //添加元素到Home对象中
       home.add(new Dog());
       home.add(new Cat());

       //创建主人对象
       Owner owner = new Owner();
       //让主人喂食所有的宠物
       home.action(owner);
   }
}

10 备忘录模式

定义:

        备忘录模式又称快照模式,是一种行为型设计模式。它可以在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态,以便在需要的时候恢复到原先保存的状态

结构:

  • 发起人(Originator):需要保存和恢复状态的对象。它创建一个备忘录对象,用于存储当前对象的状态,也可以使用备忘录对象恢复自身的状态。

  • 备忘录(Memento):存储源发器对象的状态。备忘录对象可以包括一个或多个状态属性,源发器可以根据需要保存和恢复状态。

  • 管理者(Caretaker):负责保存备忘录对象,但不能修改备忘录对象的内容。它可以存储多个备忘录对象,并决定何时将备忘录恢复给源发器。

实现:

发起人:

public class GameRole {

   private int vit; //生命力
   private int atk; //攻击力
   private int def; //防御力

   //初始化内部状态
   public void initState(){
       this.vit = 100;
       this.atk = 100;
       this.def = 100;
   }

   //战斗
   public void fight(){
       this.vit = 0;
       this.atk = 0;
       this.def = 0;
   }

   //保存角色状态功能
   public RoleStateMemento saveState(){
       return new RoleStateMemento(vit,atk,def);
   }

   //恢复角色初始化状态
   public void recoverState(RoleStateMemento roleStateMemento){
       //将备忘录对象中存储的状态复制给当前对象的成员
       this.vit = roleStateMemento.getVit();
       this.atk = roleStateMemento.getAtk();
       this.def = roleStateMemento.getDef();
   }

   //展示状态功能
   public void stateDisplay(){
       System.out.println("角色生命力:"+vit);
       System.out.println("角色攻击力:"+atk);
       System.out.println("角色防御力:"+def);
   }

   public int getVit() {
       return vit;
   }

   public void setVit(int vit) {
       this.vit = vit;
   }

   public int getAtk() {
       return atk;
   }

   public void setAtk(int atk) {
       this.atk = atk;
   }

   public int getDef() {
       return def;
   }

   public void setDef(int def) {
       this.def = def;
   }
}

备忘录对象

public class RoleStateMemento {
   private int vit; //生命力
   private int atk; //攻击力
   private int def; //防御力

   public RoleStateMemento(int vit, int atk, int def) {
       this.vit = vit;
       this.atk = atk;
       this.def = def;
   }

   public RoleStateMemento() {
   }

   public int getVit() {
       return vit;
   }

   public void setVit(int vit) {
       this.vit = vit;
   }

   public int getAtk() {
       return atk;
   }

   public void setAtk(int atk) {
       this.atk = atk;
   }

   public int getDef() {
       return def;
   }

   public void setDef(int def) {
       this.def = def;
   }
}

备忘录对象管理对象

public class RoleStateCaretaker {
   //RoleStateMemento
   private RoleStateMemento roleStateMemento;

   public RoleStateMemento getRoleStateMemento() {
       return roleStateMemento;
   }

   public void setRoleStateMemento(RoleStateMemento roleStateMemento) {
       this.roleStateMemento = roleStateMemento;
   }
}

测试类

public class Client {
   public static void main(String[] args) {
       System.out.println("------大战boss前------");
       //创建游戏角色对象
       GameRole gameRole = new GameRole();
       gameRole.initState(); //初始化状态操作
       gameRole.stateDisplay();
       //将游戏游戏角色内部状态备份
       //创建管理者对象
       RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
       roleStateCaretaker.setRoleStateMemento(gameRole.saveState());

       System.out.println("------大战boss后------");
       //损耗严重
       gameRole.fight();
       gameRole.stateDisplay();

       System.out.println("------恢复之前的状态------");
       gameRole.recoverState(roleStateCaretaker.getRoleStateMemento());
       gameRole.stateDisplay();
   }
}



 

11. 解释器模式

概念:

        解释器模式是指给定一门语言,定义它的文法的一种表示(如:加减乘除表达式和正则表达式等),然后再定义一个解释器,该解释器用来解释我们的文法表示(表达式)。解释器模式的结构与组合模式相似,不过其包含的组成元素比组合模式多,而且组合模式是对象结构型模式,而解释器模式是类行为型模式。

结构:

  • 抽象解释器(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。

  • 终结符解释器(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。

  • 非终结符解释器(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。

  • 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。

实现:

public abstract class AbstractExpression {

   public abstract int interpret(Context context);
}
public class Minus extends AbstractExpression{

   //-号左边的表达式
   private AbstractExpression left;
   //-号右边的表达式
   private AbstractExpression right;

   public Minus(AbstractExpression left, AbstractExpression right) {
       this.left = left;
       this.right = right;
   }

   @Override
   public int interpret(Context context) {
       //将左边表达式的结果和右边表达式的结果进行相减
       return left.interpret(context) - right.interpret(context);
   }

   @Override
   public String toString() {
       return "("+left.toString() + " - " +right.toString()+")";
   }
}
public class Plus extends AbstractExpression{

   //+号左边的表达式
   private AbstractExpression left;
   //+号右边的表达式
   private AbstractExpression right;

   public Plus(AbstractExpression left, AbstractExpression right) {
       this.left = left;
       this.right = right;
   }

   @Override
   public int interpret(Context context) {
       //将左边表达式的结果和右边表达式的结果进行相加
       return left.interpret(context) + right.interpret(context);
   }

   @Override
   public String toString() {
       return "("+left.toString() + " + " +right.toString()+")";
   }
}
public class Variable extends AbstractExpression {
   //声明存储变量名的成员变量
   private String name;

   public Variable(String name) {
       this.name = name;
   }

   @Override
   public int interpret(Context context) {
       //直接返回变量的值
       return context.getValue(this);
   }

   @Override
   public String toString() {
       return  name;
   }
}
public class Context {
   //定义一个map集合,用来存储变量及对应的值
   private Map<Variable,Integer> map = new HashMap<>();

   //添加变量的功能
   public void assign(Variable var,Integer value){
       map.put(var,value);
   }

   //根据变量获取对应的值
   public int getValue(Variable var){
       return map.get(var);
   }
}
public class Client {
   public static void main(String[] args) {
       //创建环境对象
       Context context = new Context();

       //创建多个变量对象
       Variable a = new Variable("a");
       Variable b = new Variable("b");
       Variable c = new Variable("b");
       Variable d = new Variable("d");

       //将变量存储到环境对象中
       context.assign(a,1);
       context.assign(b,2);
       context.assign(c,3);
       context.assign(d,4);

       //获取抽象语法树 a+b-c+d
       AbstractExpression abstractExpression = new Minus(a,new Plus(new Minus(b,c),d));

       //解释(计算)
       int interpret = abstractExpression.interpret(context);
       System.out.println(abstractExpression+"="+interpret);
   }
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值