开源项目YtyMark文本编辑器--UI界面相关功能(关于设计模式的实战运用)

🙌开源项目地址

🌍 GitHub 开源地址(YtyMark-java)

欢迎提交 PR、Issue、Star ⭐️!

📌1. 简述

YtyMark-java项目分为两大模块:

  • UI界面(ytyedit-mark)

  • markdown文本解析和渲染(ytymark)

本文主要内容为UI界面相关功能。

关于markdown文本解析器UI界面的实现。在这整个流程中,如果通过设计模式实现高内聚低耦合,可重用,易于阅读,易于扩展,易于维护等。

复制代码
YtyMark-java
├── ytyedit-mark/
│   ├── src/
│   │   ├── main/
│   │   │   ├── java/
│   │   │   │   ├── editor/             # JavaFX UI 界面
│   │   │   │   ├── enums/              # Icon图标等
│   │   │   │   ├── utils/              # 资源读取等
│   │   │   │   ├── window/             # 自定义窗口(主窗口、弹框)
│   │   │   │   ├── RenderMarkdown      # 解析和渲染
│   │   │   │   ├── YtyEditApplication  # 主程序入口
│   │   │   └── resources/
│   │   │       └── css/                # 主题样式(CSS)
│   │   │       └── fonts/              # 字体集
│   │   │       └── images/             # 图片
│   ├── README.md
│   └── pom.xml

🧩2. JavaFX 用户界面

目标:为用户提供可视化的文本输入、实时预览、编辑、保存、导出(PDF/HTML)和主题切换等功能。

使用到的设计模式

  • 工厂模式样式的创建通过工厂模式来完成。

  • 策略模式 :动态选择工具界面样式,完成UI界面的样式切换

  • 观察者模式 :识别到主题发生变化时执行重新渲染操作;样式切换后,渲染的文字样式也需要同步调整,再结合监听器(观察者模式)来实现主题变化后重新渲染文本内容,除此之外JavaFX使用了大量的监听器。

  • 单例模式:主题样式管理器统一管理全局样式,并提供统一访问入口。

  • 装饰模式 :对自定义基础弹框做定制化的扩展,实现不同场景所需的弹框。

  • 命令模式:封装工具界面中的功能点及快捷键命令。

  • 备忘录模式 :负责实现撤销恢复功能,实现精细到单字符的撤销/恢复机制。

2.1. 工厂模式

通过工厂创建样式,将默认的样式创建好,统一放入Map中保存,需要时直接从工厂中获取。

java 复制代码
public class StyleFactory {
    private static final Map<Key, Style> STYLE_MAP = new HashMap<>();

    // 预先注册默认样式
    static {
        registerStyle(WindowType.MAIN_WINDOW, ThemeType.LIGHT, new MainWindowLightStyle());
        registerStyle(WindowType.MAIN_WINDOW, ThemeType.DARK, new MainWindowDarkStyle());
        registerStyle(WindowType.DIALOG_WINDOW, ThemeType.LIGHT, new DialogWindowLightStyle());
        registerStyle(WindowType.DIALOG_WINDOW, ThemeType.DARK, new DialogWindowDarkStyle());
    }

    public static void registerStyle(WindowType type, ThemeType theme, Style style) {
        STYLE_MAP.put(new Key(type, theme), style);
    }

    public static Style getStyle(WindowType type, ThemeType theme) {
        Style style = STYLE_MAP.get(new Key(type, theme));
        if (style == null) {
            throw new RuntimeException("窗口类型或主题类型不支持: " + type + " - " + theme);
        }
        return style;
    }

    ...
}

2.2. 策略模式

动态选择工具界面样式,完成UI界面的样式切换。并支持对已有窗口样式的自由组合,比如深色的主窗口+浅色的弹框。

使用setTheme(ThemeType)方法可以快速切换已经搭配好的主题 ;使用setStyle可以灵活指定不同窗口的样式。

java 复制代码
public class ThemeContext {
    ...

    // 设置样式
    public void setTheme(ThemeType theme) {
        WindowType[] values = WindowType.values();
        for (WindowType windowType : values) {
            this.themeManager.setStyle(windowType, theme);
        }
    }

    // 自定义设置不同窗体不同样式
    public void setStyle(WindowType type, ThemeType theme) {
        this.themeManager.setStyle(type, theme);
    }

    // 主题切换
    public void switchTheme() {
        // 清空之前的样式
        scene.getStylesheets().clear();
        this.themeManager.applyStyle(WindowType.MAIN_WINDOW, scene);
    }

}

2.3. 观察者模式和单例模式

识别到主题发生变化时执行重新渲染操作。样式切换后,渲染的文字样式也需要同步调整,结合监听器(观察者模式)来实现主题变化后重新渲染文本内容,除此之外JavaFX使用了大量的监听器。

自定义的主题监听器接口:

java 复制代码
public interface ThemeChangeListener {
    void onThemeChanged();
}

主题监听器将有主题管理类 来统一管理,并结合单例模式 ,使得主题管理器全局唯一,并提供统一访问入口ThemeManager.getInstance()

java 复制代码
public class ThemeManager {

    private static ThemeManager instance;
    private final Map<WindowType, Style> currentStyles = new HashMap<>();
    private final List<ThemeChangeListener> listeners = new ArrayList<>();


    private ThemeManager() {
        // 默认主窗口白天模式,弹窗白色模式
        currentStyles.put(WindowType.MAIN_WINDOW, new MainWindowLightStyle());
        currentStyles.put(WindowType.DIALOG_WINDOW, new DialogWindowLightStyle());
    }

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

    public void setStyle(WindowType type, ThemeType theme) {
        currentStyles.put(type, StyleFactory.getStyle(type, theme));
        // 通知所有观察者主题已变更
        this.notifyThemeChanged();
    }

    ...

    // 注册观察者
    public void addThemeChangeListener(ThemeChangeListener listener) {
        listeners.add(listener);
    }
    // 注销观察者
    public void removeThemeChangeListener(ThemeChangeListener listener) {
        listeners.remove(listener);
    }

    // 通知所有观察者
    private void notifyThemeChanged() {
        for (ThemeChangeListener listener : listeners) {
            listener.onThemeChanged();
        }
    }
}

通用弹框渲染处理类实现了监听器接口,在创建时注册到监听器中

java 复制代码
public class GenericDialog implements ThemeChangeListener {

    public GenericDialog(Stage owner) {
        ...

        this.themeManager.addThemeChangeListener(this);

        ...
    }

    /**
     * 订阅主题样式变更,主题变更后自动切换弹窗样式
     */
    @Override
    public void onThemeChanged() {
        // 清空之前的样式
        dialogScene.getStylesheets().clear();
        themeManager.applyStyle(WindowType.DIALOG_WINDOW,dialogScene);
    }
}

渲染处理类监听相关源码

java 复制代码
public class RenderMarkdown  implements ThemeChangeListener {
    public RenderMarkdown(Tab tab) {
        ...

        // 注册自己为 ThemeContext 的监听者
        ThemeManager.getInstance().addThemeChangeListener(this);

        ...
    }
    /**
     * 订阅主题样式变更,主题变更后自动重新渲染内容
     */
    @Override
    public void onThemeChanged() {
        // 主题变更后自动渲染
        renderMarkdown(null);
    }
}

2.4. 装饰模式

对自定义基础弹框做定制化的扩展,实现不同场景所需的弹框。弹框装饰类通过组合的方式,对通用弹框做定制化设置

java 复制代码
public abstract class DialogDecorator {
    private GenericDialog dialog;

    public DialogDecorator(GenericDialog dialog) {
        this.dialog = dialog;
    }

    public void removeLogo(boolean flag){
        dialog.removeLogo(flag);
    }
    // 委托设置标题
    public void setTitle(String title) {
        dialog.setTitle(title);
    }

    // 委托设置主体内容
    public void setContent(Node content) {
        dialog.setContent(content);
    }

    // 委托添加内容
    public void addContent(Node node) {
        dialog.addContent(node);
    }

    // 委托设置底部按钮区域
    public void setFooter(Node node) {
        dialog.setFooter(node);
    }

    // 委托添加底部按钮
    public void addFooter(Node node) {
        dialog.addFooter(node);
    }

    // 显示并阻塞,返回用户操作结果
    public void showAndWait() {
        dialog.showAndWait();
    }

}

2.5. 命令模式和备忘录模式

封装工具界面中的功能点及快捷键命令。备忘录模式负责实现撤销恢复 功能,实现精细到单字符的撤销/恢复机制,主要涉及的类:管理文本状态TextEditorOriginator、管理撤销和恢复的栈UndoRedoCaretaker

java 复制代码
public class UndoRedoCaretaker {

    private Deque<TextMemento> undoStack = new ArrayDeque<>();
    private Deque<TextMemento> redoStack = new ArrayDeque<>();
    private TextEditorOriginator originator;
    private boolean isUndoRedo = false;
    private static final int MAX_HISTORY = 1000; // 最多保存 1000 步

    public UndoRedoCaretaker(TextEditorOriginator originator) {
        this.originator = originator;
        // 存入初始状态,确保撤销可用
        undoStack.push(originator.save());
    }

    // 保存
    public void saveState(String text, int caretPosition) {
       ...
    }

    // 撤销
    public void undo() {
        ...
    }
    // 恢复
    public void redo() {
        ...
    }
    public boolean isUndoRedo() {
        return isUndoRedo;
    }
    public void clear() {
        undoStack.clear();
        redoStack.clear();
    }

}

📸 3. 界面截图预览

白天模式的截图:

夜间模式的截图:

✏️4. 总结

YtyMark 编辑器界面UI相关功能,将多种设计模式融入到实际应用中,从实践中积累程序设计经验。

更多详细内容可以前往笔者微信公众号回复:设计模式,来获取,后续有关设计模式的新资料都可以从这个入口获取到。

  • 秘籍1设计模式手册:《掌握设计模式:23种经典模式实践、选择、价值与思想》

  • 秘籍2 练手项目:设计模式实战项目--markdown文本编辑器软件开发(已开源

查看往期设计模式文章的:设计模式

超实用的SpringAOP实战之日志记录

2023年下半年软考考试重磅消息

通过软考后却领取不到实体证书?

计算机算法设计与分析(第5版)

Java全栈学习路线、学习资源和面试题一条龙

软考证书=职称证书?

软考中级--软件设计师毫无保留的备考分享

三连支持!!!

相关推荐
12lf26 分钟前
4月21号
java
spencer_tseng34 分钟前
List findIntersection & getUnion
java·list
weixin_4565881540 分钟前
【java 13天进阶Day05】数据结构,List,Set ,TreeSet集合,Collections工具类
java·数据结构·list
李少兄1 小时前
IntelliJ IDEA 新版本中 Maven 子模块不显示的解决方案
java·maven·intellij-idea
康提扭狗兔1 小时前
code review时线程池的使用
java·代码复审
Hy行者勇哥1 小时前
从华为云物联网设备影子抽取数据显示开发过程演练
java·struts·华为云
-曾牛1 小时前
GitHub创建远程仓库
java·运维·git·学习·github·远程工作
Craaaayon1 小时前
JVM虚拟机-类加载器、双亲委派模型、类装载的执行过程
java·jvm·spring boot·后端·算法·java-ee·tomcat
Auroral1561 小时前
结构型模式:适配器模式
设计模式
百锦再1 小时前
SQLiteDatabase 增删改查(CRUD)详细操作
android·xml·java·ide·android studio·安卓