日常开发过程过程中。树形结构运用的非常频繁。
例如:公司组织结构、各种分类结构、分组结构等等。


SET FOREIGN_KEY_CHECKS = 0;
CREATE TABLE IF NOT EXISTS `tbl_sapo_group` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`code` varchar(100) NOT NULL COMMENT '唯一编码',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新时间',
`name` varchar(255) NOT NULL COMMENT '名称',
`detail` varchar(255) DEFAULT NULL COMMENT '详情',
`status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '状态:0-无效,1-有效,2-编辑',
`group_type` varchar(100) NOT NULL COMMENT '组类型',
PRIMARY KEY (`id`),
UNIQUE KEY `uni_idx_group_code` (`code`),
KEY `idx_group_group_type` (`group_type`),
CONSTRAINT `fk_group_group_type` FOREIGN KEY (`group_type`) REFERENCES `tbl_sapo_group_type` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='组';
CREATE TABLE IF NOT EXISTS `tbl_sapo_group_rel` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新时间',
`parent_code` varchar(100) NOT NULL COMMENT '父节点代码,tbl_sapo_group表code',
`child_code` varchar(100) NOT NULL COMMENT '子节点代码,tbl_sapo_group表code',
`status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '状态:0-无效,1-有效,2-编辑',
`group_rel_type` varchar(100) NOT NULL COMMENT '组关系类型代码,来自tbl_sapo_group_rel_type表code',
`tree_code` varchar(100) NOT NULL COMMENT '树节点代码,tbl_sapo_tree表code',
PRIMARY KEY (`id`),
KEY `idx_group_rel_child_code` (`child_code`),
KEY `idx_group_rel_parent_code` (`parent_code`),
KEY `idx_group_rel_group_rel_type` (`group_rel_type`),
KEY `idx_group_rel_tree_code_status_parent_code_child_code` (`tree_code`,`status`,`parent_code`,`child_code`),
CONSTRAINT `fk_group_rel_child_code` FOREIGN KEY (`child_code`) REFERENCES `tbl_sapo_group` (`code`),
CONSTRAINT `fk_group_rel_group_rel_type` FOREIGN KEY (`group_rel_type`) REFERENCES `tbl_sapo_group_rel_type` (`code`),
CONSTRAINT `fk_group_rel_parent_code` FOREIGN KEY (`parent_code`) REFERENCES `tbl_sapo_group` (`code`),
CONSTRAINT `fk_group_rel_tree_code` FOREIGN KEY (`tree_code`) REFERENCES `tbl_sapo_tree` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='组关系';
CREATE TABLE IF NOT EXISTS `tbl_sapo_group_rel_type` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`code` varchar(100) NOT NULL COMMENT '唯一编码',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新时间',
`name` varchar(255) NOT NULL COMMENT '名称',
`detail` varchar(255) DEFAULT NULL COMMENT '详情',
`status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '状态:0-无效,1-有效,2-编辑',
PRIMARY KEY (`id`),
UNIQUE KEY `uni_idx_group_rel_type_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='组关系类型';
CREATE TABLE IF NOT EXISTS `tbl_sapo_group_type` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`code` varchar(100) NOT NULL COMMENT '唯一编码',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新时间',
`name` varchar(255) NOT NULL COMMENT '名称',
`detail` varchar(255) DEFAULT NULL COMMENT '详情',
`status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '状态:0-无效,1-有效,2-编辑',
PRIMARY KEY (`id`),
UNIQUE KEY `uni_idx_group_type_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='组类型';
CREATE TABLE IF NOT EXISTS `tbl_sapo_tree` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`code` varchar(100) NOT NULL COMMENT '唯一编码',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新时间',
`name` varchar(255) NOT NULL COMMENT '名称',
`detail` varchar(255) DEFAULT NULL COMMENT '详情',
`status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '状态:0-无效,1-有效,2-编辑',
PRIMARY KEY (`id`),
UNIQUE KEY `uni_idx_tree_code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='树定义';
CREATE TABLE IF NOT EXISTS `tbl_sapo_tree_group` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`create_time` datetime(3) NOT NULL COMMENT '创建时间',
`last_update_time` datetime(3) DEFAULT NULL COMMENT '最后更新时间',
`group_code` varchar(100) NOT NULL COMMENT '组代码,tbl_sapo_group表code',
`tree_code` varchar(100) NOT NULL COMMENT '树代码,tbl_sapo_tree表code',
`status` int(10) unsigned NOT NULL DEFAULT 2 COMMENT '状态:0-无效,1-有效,2-编辑',
`is_root` int(10) unsigned DEFAULT NULL COMMENT '是否根节点:1-根节点,null非根节点',
PRIMARY KEY (`id`),
UNIQUE KEY `uni_idx_tree_group_tree_code_is_root` (`tree_code`,`is_root`),
KEY `idx_tree_group_group_code` (`group_code`),
CONSTRAINT `fk_tree_group_group_code` FOREIGN KEY (`group_code`) REFERENCES `tbl_sapo_group` (`code`),
CONSTRAINT `fk_tree_group_tree_code` FOREIGN KEY (`tree_code`) REFERENCES `tbl_sapo_tree` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='树包含的组';
SET FOREIGN_KEY_CHECKS = 1;
建表语句如图所示关系型数据库模型,基本满足一个系统多颗树、组可以复用的目的。
树的节点可能是一个单独的节点,也可能是一个子树的根。我们需要遍历的时候需要不同节点不同处理,使用【多态】。
但是处理的时候不要区分是何种节点,提供一种【透明化】处理方式,要实现需要引用两个模式:迭代模式、组合模式
老规矩,先引入概念,之后实现。
| 迭代器模式 | 提供一个方式来遍历集合而无需暴露集合的实现 |
| 组合模式 | 客户可以将对象的集合以及个别对象一视同仁 |
迭代器模式:
|
迭代器示例:数组实现迭代器
数组迭代器
1.当然remove可以不实现,因为可能并发remove,迭代器不安全。 我们简单处理抛出java.lang.UnsupportedOperationException 2.java5之后,集合可以使用for/in形式代替了显示的创建迭代器。 for( Object obj: collection){ } |
对于不同的集合,我们有不同的遍历方式。有没有一种通用的遍历集合的模式,屏蔽这种差异,该模式就是迭代器。
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而不暴露其内部的表示。
其实说白了,迭代器模式就是通过定义统一操作接口,来屏蔽不同底层的操作逻辑。
如果你能有一个统一的方法访问聚合中的每一个对象,你就可以编写多态的代码和这些聚合搭配。
把游走的任务放在迭代器上,而不是聚合上。这样简化了聚合的接口和实现。责任分配明晰。
符合【单一职责】,如果不使用迭代器模式,集合改变的话,例如由集合变数组,这个类必须改变,遍历方式也跟着改变。
组合模式:
允许你将对象组合成树形结构来表现“整体/部分”层次结构。
组合能让客户以一致的方式处理个别对象以及对象组合。即我们可以忽略对象组合和个别对象之间的差别,而使用相同操作。
组合模式牺牲【单一责任】获取【透明性】,透明性即客户处理组合和叶节点一视同仁。一个节点是组合还是叶节点,对客户是透明的。
|
组合模式示例:
MenuComponent
Menu
MenuItem
Waitress
|
示例:
使用迭代和组合模式实现一种通用的树形结构:
1.核心及组和组的关系。
2.该方案实现了,内部迭代器和外部迭代器。根据实际情况使用。
建表及测试数据
|
|
public abstract class GroupComponent {
public abstract Iterator<GroupComponent> createIterator();
// 首行字符空几格
protected abstract String printTreeStr(int i);
public abstract String getName();
public String printTreeStr() {
return printTreeStr(0);
};
// 打印树形解结构
protected String padding_n(int n) {
StringBuffer space = new StringBuffer("");
for (int i = 0; i < n; i++) {
space.append("-");
}
space.append("|");
return space.toString();
}
// 递归获取树形结构
public static GroupComponent getTree(String groupCode) {
// 获取通用dao
CommonDao dao = SpringUtil.getBean(CommonDao.class);
// 数据库中组详细信息model类
SapoGroup sapoGroup = dao.getObj(SapoGroup.getInstance().setCode(groupCode));
// 查询该节点所有儿子
List<SapoGroupRel> childList = dao.getObjListWithEmpty(SapoGroupRel.getInstance().setParentCode(groupCode));
// 如果没有子节点,直接新建叶子节点返回
if (childList == null || childList.size() == 0) {
LeafGroup leafGroup = new LeafGroup();
leafGroup.setLeafGroup(sapoGroup);
return leafGroup;
} else {
// 如果有子节点
Group group = new Group();
group.setGroupDetail(sapoGroup);
for (SapoGroupRel rel : childList) {
// 递归拿到上一个节点
GroupComponent child = getTree(rel.getChildCode());
group.getList().add(child);
}
return group;
}
}
}
GroupComponent public class Group extends GroupComponent {
Iterator<GroupComponent> iterator = null;
public List<GroupComponent> list = new ArrayList<GroupComponent>();
public SapoGroup groupDetail;
public SapoGroup getGroupDetail() {
return groupDetail;
}
public void setGroupDetail(SapoGroup groupDetail) {
this.groupDetail = groupDetail;
}
/*
* 打印树形层级结构
*/
protected String printTreeStr(int i) {
// 需要打印的字段
String waitPrintStr = this.groupDetail.getName();
StringBuilder sb = new StringBuilder();
sb.append(padding_n(i));
sb.append(waitPrintStr);
sb.append("\r\n");
Iterator<GroupComponent> iterator = list.iterator();
while (iterator.hasNext()) {
GroupComponent next = iterator.next();
// 递归进行遍历
String printTree = next.printTreeStr(i + 2);
sb.append(printTree);
}
return sb.toString();
}
public List<GroupComponent> getList() {
return list;
}
public void setList(List<GroupComponent> list) {
this.list = list;
}
@Override
public Iterator<GroupComponent> createIterator() {
if (iterator == null) {
iterator = new GroupIterator(list.iterator());
}
return iterator;
}
@Override
public String getName() {
return "list: " + groupDetail.getName();
}
}
Group public class LeafGroup extends GroupComponent {
private SapoGroup leafGroup;
public SapoGroup getLeafGroup() {
return leafGroup;
}
public void setLeafGroup(SapoGroup leafGroup) {
this.leafGroup = leafGroup;
}
public Iterator<GroupComponent> createIterator() {
return new NullIterator();
}
protected String printTreeStr(int i) {
// 关键字段
String waitPrintStr = this.getLeafGroup().getName();
return padding_n(i) + waitPrintStr + "\r\n";
}
/* (non-Javadoc)
* @see cn.com.fmsh.nfcos.sapo.biz.testGroup.GroupComponent#getName()
*/
@Override
public String getName() {
return "leaf: "+leafGroup.getName();
}
}
LeafGroup
public class GroupIterator implements Iterator<GroupComponent> {
Stack<Iterator<GroupComponent>> stack = new Stack<Iterator<GroupComponent>>();
public GroupIterator(Iterator<GroupComponent> iterator) {
stack.push(iterator);
}
public boolean hasNext() {
if (stack.isEmpty()) {
return false;
} else {
Iterator<GroupComponent> iterator = stack.peek();
if (!iterator.hasNext()) {
stack.pop();
return hasNext();
} else {
return true;
}
}
}
public GroupComponent next() {
if(hasNext()) {
Iterator<GroupComponent> iterator = stack.peek();
GroupComponent next = iterator.next();
stack.push(next.createIterator());
return next;
}else {
return null;
}
}
}
GroupIterator
public class NullIterator implements Iterator<GroupComponent> {
public GroupComponent next() {
return null;
}
public boolean hasNext() {
return false;
}
}
NullIterator
测试程序,遍历树形结构、打印树形结构。
@Test
public void Test() {
// 使用外部迭代器遍历
GroupComponent tree = Group.getTree("hotel");
Iterator<GroupComponent> iterator = tree.createIterator();
while (iterator.hasNext()) {
GroupComponent next = iterator.next();
// TODO 遍历操作内容
}
System.out.println("----打印树形结构-----");
// 打印树形结构
System.err.println(GroupComponent.getTree("hotel").printTreeStr());
}

本文来自博客园,作者:wanglifeng,转载请注明原文链接:https://www.cnblogs.com/wanglifeng717/p/16363485.html
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.