软件设计模式(四):观察者、组合、享元模式

前言

在这篇文章中,荔枝将会梳理软件设计模式中有关观察者模式、组合模式和享元模式的内容。其中组合模式和享元模式比较简单,重点需要理解观察者模式的机制以及为什么该模式实现了对象之间的松耦合。希望荔枝的梳理能对需要的小伙伴有帮助~~~


文章目录

前言

一、观察者模式Observer

二、组合模式Composite

三、享元模式Flyweight

总结


一、观察者模式Observer

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,依赖它的所有观察者对象都会收到通知并自动更新。这种模式跟发布订阅的流程类似,因此有些人又称该模式为发布订阅模式。观察者模式的核心思想是解耦 ,观察者模式通过将主题和观察者解耦,实现了对象之间的松耦合。当主题的状态发生改变时,所有依赖于它的观察者都会收到通知并进行相应的更新。在观察者模式中,主题只知道观察者的存在,并不知道观察者的具体实现。当主题状态发生改变时,它只需要通知观察者即可,而不需要关心观察者的具体实现。

关于观察者模式和发布订阅模式的异同,也有些博主的文章进行区分,这里可以看:

https://juejin.cn/post/6844903603107266567?searchId=202309082143393C968B11EA74CF13EAF1

观察者模式的结构组成如下,一般来说我们都会定义一个事件类,当触发了这个事件就会由观察者调用对应的事件执行方法。

在下面的demo中,我们定义了事件类、观察者接口及其对应的实现类。当我们实例化观察者对象之后就会调用addActionListener方法并将传入对应的观察者实例对象作为参数。这个时候所有的观察者对象就会被加入到对应的观察者列表中并等待对应事件触发,这里是一个按键的操作buttonPressed()。当事件触发后观察者对象就会被观察者列表中一 一获取出来并调用对应的actionPerformed方法。

java 复制代码
package com.crj.observer;

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


public class Test {
	public static void main(String[] args) {
		Button b = new Button();
		b.addActionListener(new MyActionListener1());
		b.addActionListener(new MyActionListener2());
		b.buttonPressed();
	}
}

/**
 * 观察者观察的对象
 */
class Button {
	
	private List<ActionListener> actionListeners = new ArrayList<ActionListener>();
	
	public void buttonPressed() {
		ActionEvent e = new ActionEvent(System.currentTimeMillis(),this);
		for(int i=0; i<actionListeners.size(); i++) {
			ActionListener l = actionListeners.get(i);
			l.actionPerformed(e);
		}
	}
	
	public void addActionListener(ActionListener l) {
		actionListeners.add(l);
	}
}

//观察者
interface ActionListener {
	public void actionPerformed(ActionEvent e);
}

class MyActionListener1 implements ActionListener {

	public void actionPerformed(ActionEvent e) {
		System.out.println("button pressed!");
	}
}

class MyActionListener2 implements ActionListener {

	public void actionPerformed(ActionEvent e) {
		System.out.println("button pressed 2!");
	}
}

/**
 * 事件类
 */
class ActionEvent {
	
	long when;
	Object source;
	
	public ActionEvent(long when, Object source) {
		super();
		this.when = when;
		this.source = source;
	}

	public long getWhen() {
		return when;
	}

	//事件源对象
	public Object getSource() {
		return source;
	}
	
}

这里可能会有疑问,为什么这就是观察者模式了?在前面我们提及观察者模式其实是一种松耦合的机制,它降低了对象之间的耦合度,当一个对象的状态发生改变时,依赖它的所有观察者对象都会收到通知并自动更新。在这段demo中我们借助一个事件类定义获取事件源对象的方法,同时将不同观察者对象的实例放入了一个list列表,此时观察者们会等待事件触发并获得它们所依赖的(观察 | 监听)对象的变化信息(这里指的是方法的触发),这其实就是观察者模式的机制。


二、组合模式Composite

组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次,它创建了对象组的树形结构,也提供了修改相同对象组的方式。可以说,组合模式是树状结构的专用模式。

其实跟树形数据结构类似,区分根节点和叶节点,将LeafNode和BranchNode通过tree的方式组合在一起,根节点下的子节点可以是一个根节点。

java 复制代码
package com.crj.composite;

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

abstract class Node {
    abstract public void p();
}

class LeafNode extends Node {
    String content;
    public LeafNode(String content) {this.content = content;}

    @Override
    public void p() {
        System.out.println(content);
    }
}

class BranchNode extends Node {
    List<Node> nodes = new ArrayList<>();

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

    @Override
    public void p() {
        System.out.println(name);
    }

    public void add(Node n) {
        nodes.add(n);
    }
}


public class Main {
    public static void main(String[] args) {

        BranchNode root = new BranchNode("root");
        BranchNode chapter1 = new BranchNode("chapter1");
        BranchNode chapter2 = new BranchNode("chapter2");
        Node r1 = new LeafNode("r1");
        Node c11 = new LeafNode("c11");
        Node c12 = new LeafNode("c12");
        BranchNode b21 = new BranchNode("section21");
        Node c211 = new LeafNode("c211");
        Node c212 = new LeafNode("c212");

        root.add(chapter1);
        root.add(chapter2);
        root.add(r1);
        chapter1.add(c11);
        chapter1.add(c12);
        chapter2.add(b21);
        b21.add(c211);
        b21.add(c212);

        tree(root, 0);

    }

    static void tree(Node b, int depth) {
        for(int i=0; i<depth; i++) System.out.print("--");
        b.p();

        if(b instanceof BranchNode) {
            for (Node n : ((BranchNode)b).nodes) {
                tree(n, depth + 1);
            }
        }
    }
}

三、享元模式Flyweight

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。享元模式尝试重用现有的同类对象 ,如果未找到匹配的对象,则创建新对象。​​​​​​​享元模式在Java里面的一个比较常见的应用就是对字符和字符串的存储。

java 复制代码
package com.crj.flyweight;

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

class Bullet{
    public UUID id = UUID.randomUUID();
    boolean living = true;

    @Override
    public String toString() {
        return "Bullet{" +
                "id=" + id +
                '}';
    }
}

public class BulletPool {
    List<Bullet> bullets = new ArrayList<>();
    {
        for(int i=0; i<5; i++) bullets.add(new Bullet());
    }

    public Bullet getBullet() {
        for(int i=0; i<bullets.size(); i++) {
            Bullet b = bullets.get(i);
            if(!b.living) return b;
        }

        return new Bullet();
    }

    public static void main(String[] args) {
        BulletPool bp = new BulletPool();

        for(int i=0; i<10; i++) {
            Bullet b = bp.getBullet();
            System.out.println(b);
        }
    }

}

享元模式相当于将创建的对象放进一个类似对象池的东西,需要的时候就会将对象激活并给出去,只有在不够的时候才会重新new一个对象。这其实也是一种池化的思想。


总结

到现在荔枝已经学习了十种软件设计模式了,这些设计模式确实会在代码结构层面带来较好的优化,使得可拓展性更好,同时设计模式之间也是存在关联的,我们正常在使用的时候也可能会同时使用一种或多种设计模式。而对于设计模式的选择,则应该是适合业务的才是最好的哈哈哈哈。

今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

相关推荐
吾与谁归in3 小时前
【C#设计模式(22)——策略模式(Stratege Pattern)】
设计模式·c#·策略模式
犬余9 小时前
设计模式之享元模式:看19路棋盘如何做到一子千面
java·设计模式·享元模式
机器视觉知识推荐、就业指导19 小时前
C++设计模式:解释器模式(简单的数学表达式解析器)
c++·设计模式·解释器模式
ADRU20 小时前
设计模式-责任链模式
java·设计模式·责任链模式
我是苏苏1 天前
设计模式01:创建型设计模式之单例、简单工厂的使用情景及其基础Demo
java·开发语言·设计模式
帅到爆的努力小陈1 天前
面向对象的设计原则与设计模式
设计模式
肘击鸣的百k路1 天前
java设计模式
设计模式
bandaoyu1 天前
【设计模式】命令模式
设计模式·命令模式
whynogome1 天前
快速理解24种设计模式
设计模式
码农爱java1 天前
设计模式--装饰器模式【结构型模式】
java·设计模式·面试·装饰器模式·原理·23 中设计模式