Java常见的几种设计模式[转]

转载设计模式

0.设计原则

设计原则一句话归纳目的
开闭原则对扩展开放,对修改关闭降低维护带来的新风险
依赖倒置原则高层不应该依赖低层,要面向接口编程更利于代码结构的升级扩展
单一职责原则一个类只干一件事,实现类要单一便于理解,提高代码的可读性
接口隔离原则一个接口只干一件事,接口要精简单一功能解耦,高聚合、低耦合
迪米特法则不该知道的不要知道,一个类应该保持对其它对象最少的了解,降低耦合度只和朋友交流,不和陌生人说话,减少代码臃肿
里氏替换原则不要破坏继承体系,子类重写方法功能发生改变,不应该影响父类方法的含义防止继承泛滥
合成复用原则尽量使用组合或者聚合关系实现代码复用,少使用继承降低代码耦合

1.单例设计模式

推荐方式:双重检测、饿汉模式、静态内部类、枚举。

①懒汉模式

延迟加载,只有在真正使用的时候才会开始实例化。

写法一:

public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

非线程安全,只限于单线程,多线程使用适可能会出现多个实例,强烈不推荐使用。

写法二:

public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

使用同步方法保证线程安全(多个线程调用getInstance方法时,只有一个线程会拿到执行权,其他线程等待),效率低(不管有没有执行初始化都会执行加锁),不推荐使用。

方法三:

public class Singleton {
    private static Singleton instance;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

跟方法一一样可能会出现多个实例(多个线程执行if (instance == null) {,还未来得及创建实例),强烈不推荐使用。

方法四:

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

双重检测(Double-Check),进行了两次instance == null判断,用于确保线程安全,只会存在一个实例。优点:线程安全、延迟加载、效率较高,推荐使用。

编译器(JIT),CPU有可能对指令进行重排序,导致使用到尚未初始化的实例,可以通过添加volatile关键字进行修饰,对于volatile修饰的字段,可以防止指令重排。

②饿汉模式

类加载的初始化阶段就完成了实例的初始化,本质上就是借助于jvm类加载机制来保证实例的唯一性。

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

优点:写法简单,类加载时完成实例化,避免线程同步问题。
缺点:因为类加载时完成实例化(没有延迟加载),如果该类在应用程序运行生命周期中都没有使用过,会造成一定的内存浪费。

③静态内部类

和俄汉模式类似,都是通过类加载来保证初始化实例只有一个线程。由于饿汉模式没有延迟加载的机制,静态内部类在Singleton类被装载时并不会立即实例化,而是在需要实例化时(懒加载),调用getInstance方法(主动使用SingletonHolder类),才会装载SingletonHolder类,从而完成Singleton的实例化。

public class Singleton {

    private Singleton() {
    }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static synchronized Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

④枚举

public enum Singleton {
    INSTANCE;
  
    public void print() {
    }
}

线程安全,调用效率高,不能延时加载,可以防止反射和反序列化调用(防止反序列化重新创建新的对象)。推荐使用

关于反序列化的问题

如果实例是通过反序列化方式生成的, JVM是不会调用自己构造函数,那么就会导致反序列化生成的实例和单例代码生成的实例不是同一个。采用枚举方式实现单例不会出现该问题,因为枚举默认实现反序列化。

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("singletonSerial"));
Singleton instance =(Singleton)ois.readObject();

解决办法如下:

  • 类实现序列化Serializable,并定义serialVersionUID版本号
  • 类定义Object readResolve() throws ObjectStreamException方法
public class Singleton implements Serializable {
    static final long serialVersionUID = 42L;

    private Singleton() {
    }

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static synchronized Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    Object readResolve() throws ObjectStreamException {
        return SingletonHolder.INSTANCE;
    }
}

源码中单例的应用:

//饿汉模式
java.lang.Runtime;
//懒汉模式
org.springframework.aop.framework.ProxyFactoryBean;
//Double-Check
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
//Double-Check
org.springframework.core.ReactiveAdapterRegistry;
//Double-Check
org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
//饿汉模式
java.util.Currency

2.工厂设计模式

定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。

应用场景:

  • 当你不知道使用对象的确切类型的时候
  • 当你希望为库或框架扩展其内部组件的方法时

①简单工厂

一般简单工厂定义实例时会通过static来修饰,故也称为静态工厂。严格来说简单工厂不是一种设计模式,而是一种编码习惯。

  • 简单工厂模式不在 GoF 23 种设计模式之列。
  • 简单工厂每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度,违背了“开闭原则”。
public class SimpleFactory {
    public static Product createProduct(String type) {
        if (type.equals("xxx")) {
            return new XXXProduct();
        } else if (type.equals("yyy")) {
            return new YYYProduct();
        }

        return null;
    }
}

多方法工厂,对简单工厂进行改进,不需要传递type。

class MultiMethodFactory {
    public static Product createXXXProduct() {
        return new XXXProduct();
    }

    public static Product createYYYProduct() {
        return new YYYProduct();
    }
}

②工厂方法

简单工厂模式违背了开闭原则,而工厂方法模式是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

工厂方法模式的主要角色如下:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
  • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
public class AbstractFactoryTest {
    public static void main(String[] args) {
        AbstractFactory factory = new ConcreteFactory1();//new ConcreteFactory2();
        Product product = factory.newProduct();
        product.show();
    }
}

//抽象产品:提供了产品的接口
interface Product {
    void show();
}

//具体产品1:实现抽象产品中的抽象方法
class ConcreteProduct1 implements Product {
    public void show() {
        System.out.println("具体产品1显示...");
    }
}

//具体产品2:实现抽象产品中的抽象方法
class ConcreteProduct2 implements Product {
    public void show() {
        System.out.println("具体产品2显示...");
    }
}

//抽象工厂:提供了厂品的生成方法
interface AbstractFactory {
    Product newProduct();
}

//具体工厂1:实现了厂品的生成方法
class ConcreteFactory1 implements AbstractFactory {
    public Product newProduct() {
        System.out.println("具体工厂1生成-->具体产品1...");
        return new ConcreteProduct1();
    }
}

//具体工厂2:实现了厂品的生成方法
class ConcreteFactory2 implements AbstractFactory {
    public Product newProduct() {
        System.out.println("具体工厂2生成-->具体产品2...");
        return new ConcreteProduct2();
    }
}

③抽象工厂

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

抽象工厂模式的主要角色如下(和工厂方法模式一样,但抽象工厂中方法个数不同,抽象产品的个数也不同):

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
  • 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
public class FarmTest {
    public static void main(String[] args) {
        Farm farm = new SGfarm();//new SRfarm();
        Animal animal = farm.newAnimal();
        Plant plant = farm.newPlant();
        animal.show();
        plant.show();
    }
}

//抽象产品:动物类
interface Animal {
    void show();
}

//具体产品:马类
class Horse implements Animal {

    public void show() {
        System.out.println("动物类:马");
    }
}

//具体产品:牛类
class Cattle implements Animal {

    public void show() {
        System.out.println("动物类:牛");
    }
}

//抽象产品:植物类
interface Plant {
    void show();
}

//具体产品:水果类
class Fruitage implements Plant {

    public void show() {
        System.out.println("植物类:水果");
    }
}

//具体产品:蔬菜类
class Vegetables implements Plant {

    public void show() {
        System.out.println("植物类:蔬菜");
    }
}

//抽象工厂:农场类
interface Farm {
    Animal newAnimal();

    Plant newPlant();
}

//具体工厂:韶关农场类
class SGfarm implements Farm {
    public Animal newAnimal() {
        System.out.println("新牛出生!");
        return new Cattle();
    }

    public Plant newPlant() {
        System.out.println("蔬菜长成!");
        return new Vegetables();
    }
}

//具体工厂:上饶农场类
class SRfarm implements Farm {
    public Animal newAnimal() {
        System.out.println("新马出生!");
        return new Horse();
    }

    public Plant newPlant() {
        System.out.println("水果长成!");
        return new Fruitage();
    }
}

3.建造者模式

隐藏复合对象的创建过程(外部不需要知道产品内部结构的组成细节),它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态的创建具有复合属性的对象。建造者模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。

形象举例:

  • 在肯德基,有汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成数所谓的“套餐”。
  • 在建房子时,有墙、窗户、门、颜色、屋顶等,可以建成平房、公寓、办公楼、故宫等

应用场景:

  • 当生成的产品对象内部具有复杂的结构时;
  • 当复杂对象需要与表示分离,可能需要创建不同的表示时;
  • 当需要向客户隐藏产品内部结构的表现时。

建造者模式和工厂模式的区别:

  • 建造者模式更加注重方法的调用顺序,工厂模式注重创建对象。
  • 创建对象的力度不同,建造者模式创建复杂的对象,由各种复杂的部件组成,工厂模式创建出来的对象都一样
  • 关注重点不一样,工厂模式只需要把对象创建出来就可以了,而建造者模式不仅要创建出对象,还要知道对象由哪些部件组成。
  • 建造者模式根据建造过程中的顺序不一样,最终对象部件组成也不一样。

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

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

简单的建造者:

public class BuilderTest {
    public static void main(String[] args) {
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        Product product = director.construct();
        product.show();
    }
}

//产品角色:包含多个组成部件的复杂对象。
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.print(partA + "\t" + partB + "\t" + partC + "\t");
    }
}

//抽象建造者:包含创建产品各个子部件的抽象方法
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;
    }
}

// 具体建造者:实现了抽象建造者接口。
class ConcreteBuilder extends Builder {
    public void buildPartA() {
        product.setPartA("建造 PartA");
    }

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

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

//指挥者:调用建造者中的方法完成复杂对象的创建。
class Director {
    private Builder builder;

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

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

标准建造者示例:

public class FarmTest {
    public static void main(String[] args) {
        Farm farm = new SGfarm();//new SRfarm();
        Animal animal = farm.newAnimal();
        Plant plant = farm.newPlant();
        animal.show();
        plant.show();
    }
}

//抽象产品:动物类
interface Animal {
    void show();
}

//具体产品:马类
class Horse implements Animal {

    public void show() {
        System.out.println("动物类:马");
    }
}

//具体产品:牛类
class Cattle implements Animal {

    public void show() {
        System.out.println("动物类:牛");
    }
}

//抽象产品:植物类
interface Plant {
    void show();
}

//具体产品:水果类
class Fruitage implements Plant {

    public void show() {
        System.out.println("植物类:水果");
    }
}

//具体产品:蔬菜类
class Vegetables implements Plant {

    public void show() {
        System.out.println("植物类:蔬菜");
    }
}

//抽象工厂:农场类
interface Farm {
    Animal newAnimal();

    Plant newPlant();
}

//具体工厂:韶关农场类
class SGfarm implements Farm {
    public Animal newAnimal() {
        System.out.println("新牛出生!");
        return new Cattle();
    }

    public Plant newPlant() {
        System.out.println("蔬菜长成!");
        return new Vegetables();
    }
}

//具体工厂:上饶农场类
class SRfarm implements Farm {
    public Animal newAnimal() {
        System.out.println("新马出生!");
        return new Horse();
    }

    public Plant newPlant() {
        System.out.println("水果长成!");
        return new Fruitage();
    }
}

4.原型设计模式

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。

原型模式的克隆分为浅克隆和深克隆。

  • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
public class PrototypeTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        User user = new User();
        user.setUsername("张三");
        user.setPassword("123456");

        User copyUser = user.clone();
        copyUser.setUsername("李四");
        System.out.println(user==copyUser);
        System.out.println(user);
        System.out.println(copyUser);
    }
}

class User implements Cloneable{
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    protected User clone() throws CloneNotSupportedException {
        //需要实现深克隆,每一层对象对应的类都必须支持深克隆
        return (User)super.clone();
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

5.代理设计模式

代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

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

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

静态代理:

不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。

public class ProxyTest {
    public static void main(String[] args) {
        RealSubject subject = new RealSubject();
        Proxy proxy = new Proxy(subject);
        proxy.request();
    }
}

//抽象主题
interface Subject {
    void request();
}

//真实主题
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("访问真实主题方法...");
    }
}

//代理
class Proxy implements Subject {
    private RealSubject realSubject;

    public Proxy(RealSubject subject) {
        realSubject = subject;
    }

    @Override
    public void request() {
        preRequest();
        realSubject.request();
        postRequest();
    }

    public void preRequest() {
        System.out.println("访问真实主题之前的预处理。");
    }

    public void postRequest() {
        System.out.println("访问真实主题之后的后续处理。");
    }
}

动态代理:

通过放射在程序运行时动态的创建代理对象,效率比静态代理低,但动态代理比较灵活,可以代理多个目标对象。在Java中可以通过java.lang.reflect.InvocationHandlerjava.lang.reflect.Proxy来生成代理对象。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(String[] args) {
        Request httpReq = new HttpRequest();
        Request httpsReq = new HttpsRequest();

        test(httpReq);
        System.out.println("-------------------");
        test(httpsReq);
    }

    private static void test(Request request) {
        Request proxyObj = (Request) Proxy.newProxyInstance(
                request.getClass().getClassLoader(),
                request.getClass().getInterfaces(),
                new RequestProxy(request));

        String result = proxyObj.call();
        System.out.println("请求结果:" + result);
    }
}
interface Request {
    String call();
}

class HttpRequest implements Request {

    @Override
    public String call() {
        System.out.println("Http 执行请求...");
        return "Success";
    }
}

class HttpsRequest implements Request {

    @Override
    public String call() {
        System.out.println("Https 执行请求...");
        return "Success";
    }
}

class RequestProxy implements InvocationHandler {

    private Object request;

    public RequestProxy(Object request) {
        this.request = request;
    }

    /**
     * 代理执行
     *
     * @param proxy  代理对象
     * @param method 代理对象调用的方法
     * @param args   调用的方法中的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("拦截前...");
        Object result = method.invoke(request, args);
        System.out.println("拦截后...");
        return result;
    }
}

6.适配器设计模式

将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

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

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

类适配器模式:

//目标接口
interface Target {
    void request();
}

//适配者接口
class Adaptee {
    public void specificRequest() {
        System.out.println("适配者中的业务代码被调用!");
    }
}

//类适配器类
class ClassAdapter extends Adaptee implements Target {
    @Override  
    public void request() {
        specificRequest();
    }
}

//客户端代码
public class ClassAdapterTest {
    public static void main(String[] args) {
        System.out.println("类适配器模式测试:");
        Target target = new ClassAdapter();
        target.request();
    }
}

对象适配器:

//目标接口
interface Target {
    void request();
}

//适配者接口
class Adaptee {
    public void specificRequest() {
        System.out.println("适配者中的业务代码被调用!");
    }
}

//对象适配器类
class ObjectAdapter implements Target {
    private Adaptee adaptee;

    public ObjectAdapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void request() {
        adaptee.specificRequest();
    }
}

//客户端代码
public class ObjectAdapterTest {
    public static void main(String[] args) {
        System.out.println("对象适配器模式测试:");
        Adaptee adaptee = new Adaptee();
        Target target = new ObjectAdapter(adaptee);
        target.request();
    }
}

7.策略设计模式

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

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

  • 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
  • 环境(Context)类:持有一个策略类的引用,最终给客户端调用。
public class StrategyPattern {
    public static void main(String[] args) {
        Context c = new Context();
        Strategy s = new ConcreteStrategyA();
        c.setStrategy(s);
        c.strategyMethod();
        System.out.println("-----------------");
        s = new ConcreteStrategyB();
        c.setStrategy(s);
        c.strategyMethod();
    }
}

//抽象策略类
interface Strategy {
    void strategyMethod();    //策略方法
}

//具体策略类A
class ConcreteStrategyA implements Strategy {
    public void strategyMethod() {
        System.out.println("具体策略A的策略方法被访问!");
    }
}

//具体策略类B
class ConcreteStrategyB implements Strategy {
    public void strategyMethod() {
        System.out.println("具体策略B的策略方法被访问!");
    }
}

//环境类
class Context {
    private Strategy strategy;

    public Strategy getStrategy() {
        return strategy;
    }

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

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

8.观察者设计模式

指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

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

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

public class ObserverPattern {
    public static void main(String[] args) {
        Subject subject = new ConcreteSubject();
        Observer obs1 = new ConcreteObserver1();
        Observer obs2 = new ConcreteObserver2();
        subject.add(obs1);
        subject.add(obs2);
        subject.notifyObserver();
    }
}

//抽象目标
abstract class Subject {
    protected List<Observer> observers = new ArrayList<Observer>();

    //增加观察者方法
    public void add(Observer observer) {
        observers.add(observer);
    }

    //删除观察者方法
    public void remove(Observer observer) {
        observers.remove(observer);
    }

    public abstract void notifyObserver(); //通知观察者方法
}

//具体目标
class ConcreteSubject extends Subject {
    public void notifyObserver() {
        System.out.println("具体目标发生改变...");
        System.out.println("--------------");

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

    }
}

//抽象观察者
interface Observer {
    void response(); //反应
}

//具体观察者1
class ConcreteObserver1 implements Observer {
    public void response() {
        System.out.println("具体观察者1作出反应!");
    }
}

//具体观察者1
class ConcreteObserver2 implements Observer {
    public void response() {
        System.out.println("具体观察者2作出反应!");
    }
}
如果觉得我的文章对你有用,请随意赞赏