# Graphing **Repository Path**: Mr-Nan05/graphing ## Basic Information - **Project Name**: Graphing - **Description**: 基于javafx简单的图形绘制程序 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-05-22 - **Last Updated**: 2021-06-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Graphing - 项目名称: Graphing - 作者:宋超群 - 学号:171860642 - 邮箱:mr.nan0505@qq.com - 仓库地址:https://gitee.com/Mr-Nan05/graphing ### 引言 1. 核心技术:java + javafx + maven 2. 实现功能:实现**全部基础功能**,未实现扩展功能 ### 系统设计 1. 基本结构设计:基于MVC架构稍做修改,使业务逻辑与视图展示分离,使用外观模式封装业务逻辑,在controller层进行调度 2. 设计模式使用: - 工厂方法:使用工厂方法进行图形创建,通过运行时所需要的图形选择对应的工厂 - 单例模式:每一个工厂方法都是单例,减少了工厂实例的创建 - 原型模式:通过原型模式进行对象的复制,复制的对象也可再次复制 - 组合模式:单个图形与多个图形具有相同的管理模式,组合图形可进行与单个图形相同的操作 - 外观模式:使用外观模式将复杂的业务逻辑封装起来,只暴露简单的接口提供调用 3. UML类图模型 ![640](images/UML-package.png) ![Class Diagram](images/UML-class.png) ### 实现方案 ##### 数据结构 1. shape图形层:继承于javafx库中的图形Circle、Ellipse等,用于实现基础图形 2. model逻辑层:使用Map存储每一个图形对应的工厂对象,使用List存储每一个模型表示的具体图形,这也是实现组合模式关键因素 3. view视图层:使用javafx库中Pane与Dialog作为底层窗口,使用TilePane存储按钮,在这一层将按钮与对应的controller关联起来 4. controller控制层:将model层提供的接口与view层的显示关联,并负责分配不同选择下控制生成图形的handler ##### 设计模式 1. 工厂方法:Factory为**抽象工厂**类,其余分别为具体的工厂类,分别负责不同图形的创建工厂 ```java public class Factory implements Serializable { public Shape createShape() { return null; } public Shape createShape(double x, double y) { return null; } public Shape createShape(BaseModel model) { return null; } } ``` 2. 单例模式:使用**Initialization Demand Holder**方法,**既可以实现延迟加载,又可以保证线程安全** ```java public class CircleFactory extends Factory{ private static class InstanceHolder { private final static Factory instance = new CircleFactory(); } public static Factory getFactory() { return InstanceHolder.instance; } } ``` 3. 原型模式:通过实现**Serializable**接口与deepClone()方法实现model的**深克隆**,从而实现图形的复制粘贴 ```java public BaseModel deepClone() throws IOException, ClassNotFoundException, OptionalDataException { ByteArrayOutputStream bao=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(bao); oos.writeObject(this); ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray()); ObjectInputStream ois=new ObjectInputStream(bis); return (BaseModel)ois.readObject(); } ``` 4. 组合模式:每一个model无论是单图形还是组合图形,都使用List来存储,以达到无差别处理单图形与组合图形的目的,每个组合图形又包含了多个图形 ```java //生成单个图形 shapes.add(factories.get(modelName).createShape(this)); //生成组合图形 for(String shape: flags.keySet()){ if(flags.get(shape)) shapes.add(factories.get(shape).createShape(X, Y)); } ``` 5. 外观模式:将生成图形时的复杂逻辑(设置位置、选择图形、创建图形、关联显示)都封装在model中,只暴露生成接口给handler ```java handler = event -> { model = new TriangleModel(event.getSceneX(), event.getSceneY()); super.models.add(model); super.pane.getChildren().addAll(model.getShapes()); }; ``` ##### 特殊方法 1. 撤销操作:是用一个静态的publicModel指向最近被创建的图形,进行撤销时只需将图形从画板上删除并进行销毁即可 ```java revokeButton.setOnMouseClicked(event -> { if(publicModel != null){ publicModel.removeShape(root); publicModel = null; } }); ``` 2. 移动操作:通过反射获取运行时具体对象的具体方法(每个图形设置位置的方法不同),移动时动态调用对应的方法 ```java for(Shape s: shapes){ Method method = s.getClass().getMethod("setSite", double.class, double.class); method.invoke(s, event.getSceneX(), event.getSceneY()); ``` ### 功能介绍 1. 功能描述如下 - 点击图形对应的**按钮**,然后在屏幕上点击即可生成默认大小的图形 - 点击**组合**按钮在弹窗里选择组合的图形,点击画板即可生成默认的组合图形 - 点击**文字**按钮,单击画板开始输入文字描述,输入回车即可固定文字位置 - 点击**空选**按钮,可以对图形进行拖动,单击选中等操作 - **空选并单击选中**图形后,点击复制,然后在画板上单击即可粘贴图形 - 点击**撤销**按钮即可撤销上一个生成的图形,无论是复制的图形还是自己生成的图形 2. 界面展示如下 ![image-20210616152231858](images/image-20210616152231858.png) ![image-20210616152341266](images/image-20210616152341266.png) ![image-20210616152400967](images/image-20210616152400967.png) ![image-20210616152513242](images/image-20210616152513242.png) ### 项目总结 ​ 最初看到需要实现的各种功能时并没有什么头绪,但是回头想了想课上老师讲的设计模式,有很多都很像是在为这个作业量身定做一样,或者说那时候我才明白这个作业就是为了学习设计模式而设计,使用各种设计模式让很多问题迎刃而解