设计模式总结

设计模式分为了3类

创建型:对象的创建,让对象的创建过程与主程序进行解耦。

行为型:主要是类与对象如何进行交互,划分责任重要的有。

结构型:类与对象进行结合,组成一个更大的结构对象。

创建型设计模式

1.单例设计模式

意思就是一个类只有一个实例对象,主要可以解决全局唯一与处理资源访问冲突的问题

实现有5种

1.懒汉:使用时才创建其唯一的对象。

2.饿汉:类被加载时就创建出来,之后使用对象都使用这个对象。

3.双重检验锁:是基于懒汉进一步解决在高并发场景下的问题。

4.静态内部类:与饿汉类似,实现延迟加载。

5.枚举。

/**
 * <p>单例设计模式</p>
 *
 * @author wangxinlin@meituan.com
 * @version Singleton.class  2023-08-20 19:38
 * @since
 **/
/**
 * <p>单例设计模式</p>
 *
 * @author wangxinlin@meituan.com
 * @version Singleton.class  2023-08-20 19:38
 * @since
 **/
public class Singleton {
    /*
     *  什么是单例?就是一个类只有唯一的一个对象or实例
     * */

    //饿汉式       volatile可以防止指令重排序,避免npe
    private static volatile Singleton instance = new Singleton();

    private Singleton() {
      // 防止反射破坏单例   当然这里还有可能被序列化破坏,如果需要防止可以重写resolve 方法即可。
        if (instance != null) {
            throw new RuntimeException("不能创建");
        }
    }

    public static Singleton getInstance() {
        return instance;
    }

    //双重检验锁 懒汉式  为什么外部创建不了 因为我们私有了构造方法。那么外部创建不了对象了吗? 反射可以破坏单例,所以必须改造一下私有构造方法
    public static Singleton getInstance2() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    //静态内部类
    private static class inner {
        private static final Singleton instance = new Singleton();

    }

    public static Singleton getInstance3() {
        return inner.instance;
    }

}

2.工厂模式

工厂模式分为了简单工厂,工厂方法与抽象工厂。其中

简单工厂组成有,抽象物品类,具体物品类,工厂类。在工厂类中通过if else 判断实现不同的具体实现。不符合开闭原则(如果需要增加新的具体物品类,那么 就需要修改工厂类,所以不符合对扩展开发,对修改关闭。)

工厂方法组成有,抽象物品类,具体物品类,抽象工厂,具体工厂。每一个具体的物品类都有一个具体工厂创建,符合开闭原则。但是如果物品过多会有类爆炸的问题

抽象工厂组成有,抽象物品类,具体物品类,抽象工厂,具体工厂。抽象工厂模式中的抽象工厂定义的是一个物品的产品族(就是一类相似的物品,统一用一个抽象类)这样可以极大的减少类爆炸的问题。

/**
 * @author wangxinlin
 */
public interface Rule {

    public  String parse();
}

/**
 * <p>配置规则大全</p>
 * <p>简单工厂</p>
 *
 * @author wangxinlin@meituan.com
 * @version RuleConfig.class  2023-08-20 22:35
 * @since
 **/
public class RuleConfig {

    //第一种 if else  这里使用第二种 map  但是还是不符合开闭原则 对扩展开放对修改关闭 

    private static Map<String, Rule> ruleSource = new HashMap<>();

    static {
        ruleSource.put("xml", new XmlRule());
        ruleSource.put("json", new JsonRule());
        ruleSource.put("yaml", new YamlRule());
    }

    public static String getParseSource(String rule) {
        if (!ruleSource.containsKey(rule)) {
            return "error";
        }
        return ruleSource.get(rule).parse();
    }
}

/**
 * <p>xml</p>
 *
 * @author wangxinlin@meituan.com
 * @version XmlRule.class  2023-08-20 22:37
 * @since
 **/
public class XmlRule implements Rule {

    @Override
    public String parse() {
        return "xml";
    }
}

/**
 * <p>yaml</p>
 *
 * @author wangxinlin@meituan.com
 * @version YamlRule.class  2023-08-20 22:37
 * @since
 **/
public class YamlRule implements Rule {
    @Override
    public String parse() {
        return "yaml";
    }
}

public interface RuleAbstractFactory {


    Rule createXml();
    Rule createJson();
    Rule createYaml();
}

public class IRuleConfigParser implements RuleAbstractFactory {
    @Override
    public Rule createXml() {
        return new XmlRule();
    }

    @Override
    public Rule createJson() {
        return new JsonRule();
    }

    @Override
    public Rule createYaml() {
        return new YamlRule();
    }
}

3.建造者设计模式

建造者模式,主要用于当我们创建对象进行属性注入时,一般属性注入会有2种,当使用构造方法进行注入时如果参数过多,构造函数的参数列表会变得很长,代码在可读性和易用性上都会变差。在使用构造函数的时候,我们就容易搞错各参数的顺序,传递进错误的参数值,导致非常隐蔽的bug。这个我们为了解决这个问题就可以使用set方法进行注入,但是如果参数之间存在依赖关系(校验逻辑无处安放),或者我们想要一但对象创建好后就不再进行注入,那么显然set方法是不行的。为了解决上面的问题就可以使用建造者模式。

/**
 * <p>建造者设计模式</p>
 *
 * @author wangxinlin@meituan.com
 * @version ParamConfig.class  2023-08-23 22:59
 * @since
 **/
public class ParamConfig {

    private String name;

    private Integer age;

    public ParamConfig(Builder builder) {
        this.name = builder.getName();
        this.age = builder.getAge();
    }

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

    public static class Builder {

        //进行校验
        public ParamConfig build() {
            age = Optional.ofNullable(age).orElse(10);
            return new ParamConfig(this);
        }

        private String name;

        private Integer age;

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

        public String getName() {
            return this.name;
        }

        public Builder setAge(Integer age) {
            if (age < 0) {
                throw new RuntimeException("年龄不能小于0");
            }
            this.age = age;
            return this;
        }

        public Integer getAge() {
            return this.age;
        }

    }
}

原型设计模式

如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,这就是原型设计模式,我们是通过实现cloneable接口重新clone方法进行克隆(注意,基本数据类型为深拷贝,如果一个对象中还存在引用数据类型,则需要对引用数据类型重新clone)。也可以通过序列化与反序列化进行拷贝,序列化的方式是深拷贝。

说到拷贝就有深拷贝与浅拷贝,浅拷贝拷贝的只是引用,改变对象的值,其拷贝的引用也会改变。深拷贝则拷贝的值,改变相互不影响。

/**
 * <p>拷贝的对象</p>
 *
 * @author wangxinlin@meituan.com
 * @version Student.class  2023-09-17 14:46
 * @since
 **/
public class Student implements Cloneable, Serializable {

    private String name;

    private Integer age;

    private Teacher teacher;


    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student clone = (Student) super.clone();
        clone.setTeacher((Teacher) this.teacher.clone());
        return clone;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    public Teacher getTeacher() {
        return this.teacher;
    }

    public Student(String name, Integer age, Teacher teacher) {
        this.name = name;
        this.age = age;
        this.teacher = teacher;
    }

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

/**
 * <p></p>
 *
 * @author wangxinlin@meituan.com
 * @version Teacher.class  2023-09-17 14:46
 * @since
 **/
public class Teacher implements Cloneable, Serializable {

    private String name;


    public String getName() {
        return name;
    }

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

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

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

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

/**
 * <p>测试原型设计模式</p>
 *
 * @author wangxinlin@meituan.com
 * @version Test.class  2023-09-17 14:42
 * @since
 **/
public class Test {

    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        /*
         * 原型设计模式 主要是为了解决创建一个新对象的性能问题 原型模式通过拷贝进行创建一个对象以此来达到节省创建时间的问题
         * 原型模式 拷贝 分为了 浅拷贝与深拷贝   浅:对于引用数据类型 拷贝的只是其引用 如果修改原来的对象 则拷贝的对象也会进行修改,可以通过递归的方式进行拷贝 这就是深拷贝
         * 除了 实现cloneable接口 重写clone方法 还有 序列化与反序列化也可以实现 也是深拷贝  必须实现 Serializable
         * */

        Teacher teacher = new Teacher("张三");
        Student student = new Student("李四", 12, teacher);
        System.out.println(student);

        Student clone = (Student) student.clone();
        teacher.setName("张三2");
        System.out.println(clone);

        Teacher teacher2 = new Teacher("张三");
        Student student2 = new Student("李四", 12, teacher2);
        System.out.println(student2);

        Student clone2 = deepCopy(student2);
        teacher.setName("张三2");
        System.out.println(clone2);
    }

    public static Student deepCopy(Student student) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(student);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(outputStream.toByteArray());
        ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream);
        return (Student) inputStream.readObject();
    }
}

以上就是创建型模式

主要解决对象的创建问题,封装复杂的创建过程,解耦对象的创建代码和使用代码。

单例模式用来创建全局唯一的对象。

工厂模式用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。

建造者模式是用来创建复杂对象,可以通过设置不同的可选参数,可以定制化的创建不同的对象。

原型模式针对创建成本比较大的对象,利用对已有对象进行复制的方式进行创建,以达到节省创建时间的目的。

下面结构型设计模式

代理设计模式

代理模式,跟他名字一样比如火车票买票,原来买票直接通过窗口进行买票,但是现在买票,可以通过中间商进行买票但是那张票还是从窗口进行购买的,中间商相当于就是窗口的代理。代理可以在不改变原来代码的情况下进行扩展,符合开闭原则。后面会还有装饰器模式,跟装饰器的主要区别就是,代理强调的是隔离,装饰器强调的是增强。

必须一个功能需要计算其花费的时间,我们可以直接在原来的代码的基础上进行修改,这样很明显是不符合开闭原则的,我们还可以使用动态代理,在不改变原有的基础下,进行增加计算花费时间的功能代码。这就是代理模式

/**
 * <p>业务接口</p>
 *
 * @author wangxinlin@meituan.com
 * @version IUserController.class  2023-09-16 22:42
 * @since
 **/
public interface IUserController {

    void register();

    void login();
}

/**
 * <p>具体业务实现</p>
 *
 * @author wangxinlin@meituan.com
 * @version UserController.class  2023-09-16 22:44
 * @since
 **/
public class UserController implements IUserController {
    @Override
    public void register() {
        System.out.println("注册用户");
    }

    @Override
    public void login() {
        System.out.println("用户登陆");
    }
}

/**
 * <p>代理对象</p>
 *
 * @author wangxinlin@meituan.com
 * @version UserControllerProxy.class  2023-09-16 22:45
 * @since
 **/
public class UserControllerProxy implements InvocationHandler {

    private IUserController userController;


    public UserControllerProxy(IUserController iUserController){
        this.userController = iUserController;
    }

    public Object createProxy() {
         //创建代理对象,传3个参数第一个为类加载器,接口,实现invocationhandler接口的实现,重写invoke方法
        return Proxy.newProxyInstance(userController.getClass().getClassLoader(), userController.getClass().getInterfaces(), this);
    }

  //充血invoke方法,这里使用的反射,方法.invoke(对象,参数) 进行动态调用。
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println(start);
        Date date = new Date(System.currentTimeMillis());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd--hh:mm:ss");
        Object invoke = method.invoke(userController, args);
        long end = System.currentTimeMillis();

        System.out.println("花费了:" + (end - start) + "在" + simpleDateFormat.format(date));
        return invoke;
    }
}


/**
 * <p>代理模式测试</p>
 *
 * @author wangxinlin@meituan.com
 * @version Test.class  2023-09-16 22:38
 * @since
 **/
public class Test {
    /*代理模式分为了静态代理与动态代理,他们最大的区别就是,静态代理是在编译时,动态代理是在运行时
     一般用于比如计算一段程序的运行耗时,如果我们不进行代理 那么就需要在每一个想要测试耗时的代码都加相同的逻辑这样明显是不行的,
     所以这是我们就需要使用代理
     * */
    public static void main(String[] args) {
        IUserController userController = new UserController();

        UserControllerProxy proxy = new UserControllerProxy(userController);
        IUserController proxy1 = (IUserController) proxy.createProxy();
        proxy1.login();
    }
}

装饰器设计模式

装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能。除此之外,装饰器模式还有一个特点,那就是可以对原始类嵌套使用多个装饰器。为了满足这个应用场景,在设计的时候,装饰器类需要跟原始类继承相同的抽象类或者接口。

/**
 * <p>基础食物</p>
 *
 * @author wangxinlin@meituan.com
 * @version Food.class  2023-08-20 19:53
 * @since
 **/
public abstract  class Food {

    public Food(){}

    public abstract String getName();

    public abstract BigDecimal getPrice();
}

/**
 * <p>米饭</p>
 *
 * @author wangxinlin@meituan.com
 * @version Rice.class  2023-08-20 19:58
 * @since
 **/
public class Rice extends Food {
    @Override
    public String getName() {
        return "米饭";
    }

    @Override
    public BigDecimal getPrice() {
        return new BigDecimal("3.0");
    }
}


/**
 * <p>装饰者设计模式</p>
 *
 * @author wangxinlin@meituan.com
 * @version Decorator.class  2023-08-20 19:51
 * @since
 **/
public abstract class Decorator  extends Food{

    protected Food food;

    public Decorator(Food food){
        this.food=food;
    }

    @Override
    public String getName() {
        return this.food.getName();
    }

    @Override
    public BigDecimal getPrice() {
        return this.food.getPrice();
    }

}


/**
 * <p>添加牛奶</p>
 *
 * @author wangxinlin@meituan.com
 * @version AddMike.class  2023-08-20 19:55
 * @since
 **/
public class AddMike extends Decorator {


    public AddMike(Food food) {
        super(food);
    }

    @Override
    public String getName() {
        return super.getName() + "添加牛奶";
    }

    @Override
    public BigDecimal getPrice() {
        return super.getPrice().add(new BigDecimal("2.5"));
    }
}


/**
 * <p>测试装饰者设计模式</p>
 *
 * @author wangxinlin@meituan.com
 * @version Test.class  2023-08-20 20:01
 * @since
 **/
public class Test {

    public static void main(String[] args) {
        /*
        * 装饰器设计模式 主要作用是对原始类进行增强 代理与装饰器 很像 都可以对原始类进行增强 但是还是有区别
        * 装饰器主要是通过继承或者实现 对原始类进行增强 而代理主要是对原始类进行隔离增强
        * */

        Food rice=new Rice();
        Food mike=new AddMike(rice);
        System.out.println(mike.getName()+"一共花费:"+mike.getPrice());  //米饭添加牛奶一共花费:5.5
    }
}

适配器设计模式

适配器模式就是,调用者都统一调用a方法,但是其实现有不同的方法。那么我们就需要一个适配的一个类,让调用a方法时,实际调用自己实现的方法。

适配器模式有2种,基于继承的类适配器,还有基于组合的对象适配器。

比如现在需要将一串文本过滤,过滤的具体实现有2种,一个过滤大小写,一个过滤数字。调用者统一调用filter方法

/**
 * <p>统一适配接口类</p>
 *
 * @author wangxinlin@meituan.com
 * @version ISensitiveFilter.class  2023-09-10 22:52
 * @since
 **/
public interface ISensitiveFilter {

    public String filter(String text);
}

/**
 * <p>管理过滤方法</p>
 *
 * @author wangxinlin@meituan.com
 * @version Manager.class  2023-09-10 22:54
 * @since
 **/
public class Manager {

    private List<ISensitiveFilter> list=new ArrayList<>();

    public void addFilter(ISensitiveFilter filter){
        list.add(filter);
    }
    public String totalFilter(String text){
        //不使用适配器的话就需要在这里初始化出所有的过滤器分别调用其过滤方法,现在使用适配器把所有的过滤方法进行统一过滤如果需要修改过滤则可以在不修改原油代码的情况下进行修改
        String result=text;
        for (ISensitiveFilter iSensitiveFilter : list) {
            result = iSensitiveFilter.filter(result);
        }
      return result;
    }
}


/**
 * <p>第一种过滤器</p>
 *
 * @author wangxinlin@meituan.com
 * @version SensitiveFilterA.class  2023-09-10 22:53
 * @since
 **/
public class SensitiveFilterA {

    public  String filterLow(String text){
        return "过滤了大写的"+":"+text;
    }
}

/**
 * <p>过滤器A的适配 对象的适配器 基于组合模式</p>
 *
 * @author wangxinlin@meituan.com
 * @version AISensitiveFilter.class  2023-09-10 22:58
 * @since
 **/
public class AISensitiveFilter implements ISensitiveFilter{

    private SensitiveFilterA sensitiveFilterA;

    public AISensitiveFilter(SensitiveFilterA sensitiveFilterA){
        this.sensitiveFilterA = sensitiveFilterA;
    }
    @Override
    public String filter(String text) {

        return sensitiveFilterA.filterLow(text);
    }
}


/**
 * <p>测试适配器模式</p>
 *
 * @author wangxinlin@meituan.com
 * @version Test.class  2023-09-10 23:00
 * @since
 **/
public class Test {

    public static void main(String[] args) {
        Manager manager = new Manager();

        ISensitiveFilter a = new AISensitiveFilter(new SensitiveFilterA());
        manager.addFilter(a);
        System.out.println(manager.totalFilter("hhhh"));
    }
}

行为型设计模式

模版方法模式: 跟名字一样定义一个通用的模版进行复用。按照特定的顺序进行编排,编排中的不用场景中不同的方法进行抽象,由其子类决定其具体实现,符合开闭原则,方便扩展。

/**
 * <p>模版</p>
 *
 * @author wangxinlin@meituan.com
 * @version JdbcTemplate.class  2023-08-27 21:10
 * @since
 **/
public abstract  class Template {


    public void execute(String connect){
        connect(connect);
        createStatement();
        result();
    }

    //加载驱动
    public abstract void connect(String object);

    //建立statement对象
    public abstract  void createStatement();

    //返回结果
    public void result(){
        System.out.println("返回创建的对象");
    }
}

策略设计模式:比如一个抽奖系统,不同的几等奖对应着不同的积分(算法)按照常规,直接通过if else 即可但是写太多的if else 或者switch 并不好,所以这里就可以使用策略模式,定义一个策略接口,通过实现策略接口,实现不同的具体策略算法。这里为了不使用if else 可以使用工厂模式进行创建对象。策略模式也可以与模版方法模式一起用。

/**
 * @author wangxinlin
 */
public interface Strategy {

    public void doStrategy();
}


/**
 * <p>json策略</p>
 *
 * @author wangxinlin@meituan.com
 * @version JsonStragety.class  2023-08-27 21:18
 * @since
 **/
public class JsonStrategy implements Strategy {
    @Override
    public void doStrategy() {
        System.out.println("json");
    }
}

/**
 * <p>策略工厂</p>
 *
 * @author wangxinlin@meituan.com
 * @version StrategyFactory.class  2023-08-27 21:20
 * @since
 **/
public class StrategyFactory {

  //对象工厂
    private static Map<String, Strategy> hash = new HashMap<>();
   
 /*
 当如何在实际项目中,如何动态的对具体的策略进行注入? 
  可以利用spring的一些特性,比如,将所有的具体策略注册为一个bean对象然后通过@Resources注解进行注入
  也可以利用spring的一个扩展点进行注入。 比如 @PostConstruct 或者 bean的前置处理器后置处理器等。这里还是通过@Resources注解注入更方便
 */
    static {
        hash.put("json", new JsonStrategy());
    }

    public Strategy getStrategy(String type) {
        if (hash.containsKey(type)) {
            return hash.get(type);
        }
        return null;
    }

}

责任链设计模式

按照特定的顺序依次执行,一个请求先经过A处理器处理,然后再把请求传递给B处理器,B处理器处理完后再传递给C处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。

比如实现一个请假审批流程,

/**
 * <p>处理器类</p>
 *
 * @author wangxinlin@meituan.com
 * @version Handler.class  2023-08-27 21:43
 * @since
 **/
public abstract class Handler {

    public Handler next;

    public void setHandler(Handler handler){
        this.next=handler;
    }

    public abstract void doHandler(Integer day);
}


/**
 * <p>handlerA</p>
 *
 * @author wangxinlin@meituan.com
 * @version HandlerA.class  2023-08-27 21:45
 * @since
 **/
public class HandlerA  extends Handler{
    @Override
    public void doHandler(Integer day) {
        System.out.println("handler A 执行了");
        if (day>2){
            System.out.println("handlerA通过");
            if (next!=null){
                next.doHandler(day);
            }
        }else {
            System.out.println("HandlerA 不通过");
        }
    }
}

/**
 * <p>handlerB</p>
 *
 * @author wangxinlin@meituan.com
 * @version HandlerB.class  2023-08-27 21:48
 * @since
 **/
public class HandlerB extends Handler{
    @Override
    public void doHandler(Integer day) {
        System.out.println("handler B 执行了");
        if (day > 4) {
            System.out.println("handlerB通过");
            if (next != null) {
                next.doHandler(day);
            }
        } else {
            System.out.println("HandlerB 不通过");
        }

    }
}

public class HandlerChain {

    private Handler head = null;
    private Handler tail = null;
    
    public void addHandler(Handler handler) {
        if (head == null) {
            head = handler;
            tail = handler;
            return;
        }

        tail.setHandler(handler);
        tail = handler;
    }

    public void handle(Integer day) {
        if (head != null) {
            head.doHandler(day);
        }
    }
}

/**
 * <p>责任链</p>
 *
 * @author wangxinlin@meituan.com
 * @version Test.class  2023-08-27 21:51
 * @since
 **/
public class Test {
    public static void main(String[] args) {
        HandlerChain chain = new HandlerChain();
        chain.addHandler(new HandlerA());
        chain.addHandler(new HandlerB());
        chain.handle(3);
        /*handler A 执行了
          handlerA通过
          handler B 执行了
          HandlerB 不通过*/
    }
}

以上就是具体实现,除了以上还可以比如过滤器,拦截器,鉴权等都是其使用场景。 如果想要不修改客户端,我们可以通过自定义注解,通过将定义的执行器注册成一个bean ,通过spring的扩展点拿到这些注册成bean的对象,也能拿到其上方的注解,统一将这些注解按照一定的规则进行排序,这样就更加的符合开闭原则。

观察者设计模式

观察者又叫发布订阅模式,比如一个用户注册的功能,当注册成功后我们可能会对注册的用户发送邮件,赠送积分,等功能,当我们只有一个比如发送邮件时,可以直接写在注册的功能后面,(虽然违背了单一指责,但是也可以接受),假如有更多的事件发生,那么我们就不能都写在后面,如果新增加一个,又违背了开闭原则,如果新增事件,那么就要修改原有的代码。所以这里就可以用到观察者模式,让观察者与被观察者的行为进行解耦。如果新增,可以调用起新增的方法将其注入进去。

/**
 * @author wangxinlin
 */
public interface Observer {

    void  consumer(String message);
}

/**
 * <p>创建订阅者</p>
 *
 * @author wangxinlin@meituan.com
 * @version ConcreteObserver.class  2023-09-09 20:14
 * @since
 **/
public class ConcreteObserver implements Observer {
    @Override
    public void consumer(String message) {
        System.out.println("订阅者A接收到了" + message + "消息");
    }
}

/**
 * <p>创建二号订阅者</p>
 *
 * @author wangxinlin@meituan.com
 * @version ConcreteObserverTwo.class  2023-09-09 20:31
 * @since
 **/
public class ConcreteObserverTwo implements Observer {
    @Override
    public void consumer(String message) {
        System.out.println("订阅者B接收到了" + message + "消息");
    }
}

/**
 * <p>观察者模式又叫发布订阅模式 。创建发布者</p>
 *
 * @author wangxinlin@meituan.com
 * @version ConcreteSubject.class  2023-09-09 18:56
 * @since
 **/
public class ConcreteSubject implements Subject {

    private List<Observer> list = new ArrayList<>();

    @Override
    public void register(Observer observer) {
        if (!list.contains(observer)) {
            list.add(observer);
        }

    }

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

    @Override
    public void notifyObservers(String message) {
        for (Observer observer : list) {
            observer.consumer(message);
        }
    }
}


/**
 * @author wangxinlin
 */
public interface Subject {

    void register(Observer observer);

    void remove(Observer observer);

    //发消息
    void notifyObservers(String message);
}

/**
 * <p>测试观察者模式</p>
 *
 * @author wangxinlin@meituan.com
 * @version Test.class  2023-09-09 20:15
 * @since
 **/
public class Test {
    public static void main(String[] args) {
        Subject subject = new ConcreteSubject();
        Observer one = new ConcreteObserver();
        Observer two = new ConcreteObserverTwo();
        /*
         * 当如果需要对消息进行更多的处理时可以直接对observer 进行增加功能 更加的符合开闭原则。这也就是观察者模式的好处*/
        subject.register(one);
        subject.register(two);
        subject.notifyObservers("第一次发消息");
         /*订阅者A接收到了第一次发消息消息
           订阅者B接收到了第一次发消息消息*/
    }
}

实际上设计模式要干的事情就是解耦。创建型模式是将创建和使用代码解耦,结构型模式是将不同功能代码解耦,行为型模式是将不同的行为代码解耦,具体到观察者模式,它是将观察者和被观察者代码解耦。借助设计模式,我们利用更好的代码结构,将一大坨代码拆分成职责更单一的小类,让其满足开闭原则高内聚松耦合等特性,以此来控制和应对代码的复杂性,提高代码的可扩展性

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值