- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
组合(Composite)模式,又叫做树形模式,主要用来处理树形结构数据。是将一组对象组织成树形结构,以表示一种“部分-整体”的层次结构。让客户端可以统一单个对象和组合对象的处理逻辑。
组合模式通过以树形结构来表示“部分-整体”,使得用户对叶对象和组合对象的使用具有一致性。也就是说在组合模式中,整个树形结构的对象都属于同一种类型,用户可以对叶对象和组合对象统一处理。
组合模式主要有透明式和安全式两种分类,下面来分别说明
在该方式中,抽象构件声明了所有子类中的全部方法,这样实现抽象构件接口的所有子类都具备了全部方法,这样的好处是叶节点和枝节点对于外界没有任何区别,它们具备了完全一致的接口。但是对于叶节点有些本身不具备的方法,就可能会有安全隐患(空指针异常等)。其结构类图如下所示:
Component
:抽象构件,为叶节点和树枝节点声明公共接口,以及访问和管理子类的接口Composite
:树枝构件,组合中的分支节点对象,作用是存储和管理子部件Leaf
:树叶构件,组合中的叶节点对象,用于继承和实现抽象构件Client
:客户端前面提到透明式组合模式中,因为抽象构件声明所有子类方法,有可能会造成安全问题。所以在安全式中,将管理叶节点的方法转移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了透明式组合模式中的安全问题。但是由于树叶和树枝构件有不同的接口,因此在使用时,就不能将两种构件一概而论,对于客户端调用方而言,就失去了透明性。其结构类图如下所示:
Component
:抽象构件,为叶节点和树枝节点声明公共接口,没有访问和管理子类的接口Composite
:树枝构件,组合中的分支节点对象,作用是存储和管理子部件Leaf
:树叶构件,组合中的叶节点对象,没有对子类的管理方法Client
:客户端根据上面的类图,可以实现如下代码:
/**
* @description: 透明式抽象构件
* @author: wjw
* @date: 2022/4/3
*/
public interface Component {
/**公共操作方法**/
void operation();
/**
* 添加构件
* @param c 组合模式中的构件
*/
void add(Component c);
/**
* 移除构件
* @param c 组合模式中的构件
*/
void remove(Component c);
/**
* 获得子对象
* @param t 子对象序号
* @return 子对象
*/
Component getChild(int t);
}
/**
* @description: 树枝节点
* @author: wjw
* @date: 2022/4/3
*/
public class Composite implements Component{
private ArrayList<Component> children = new ArrayList<>();
@Override
public void operation() {
for (Component child : children) {
child.operation();
}
}
@Override
public void add(Component c) {
children.add(c);
}
@Override
public void remove(Component c) {
children.remove(c);
}
@Override
public Component getChild(int t) {
return children.get(t);
}
}
/**
* @description: 树叶节点
* @author: wjw
* @date: 2022/4/3
*/
public class Leaf implements Component{
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void operation() {
System.out.println("我是树叶节点:" + name);
}
@Override
public void add(Component c) {
}
@Override
public void remove(Component c) {
}
@Override
public Component getChild(int t) {
return null;
}
}
/**
* @description: 客户端类
* @author: wjw
* @date: 2022/4/3
*/
public class Client {
public static void main(String[] args) {
Component component = new Composite();
Component leaf1 = new Leaf("1");
Component leaf2 = new Leaf("2");
component.add(leaf1);
component.add(leaf2);
component.operation();
component.getChild(1).operation();
//这里树叶构件能调用add方法就会造成安全隐患
leaf1.add(leaf1);
}
}
客户端运行结果:
我是树叶节点:1
我是树叶节点:2
我是树叶节点:2
/**
* @description: 安全式抽象构件
* @author: wjw
* @date: 2022/4/3
*/
public interface Component {
/**公共操作方法**/
void operation();
}
/**
* @description: 树枝节点
* @author: wjw
* @date: 2022/4/3
*/
public class Composite implements Component{
private ArrayList<Component> children = new ArrayList<>();
@Override
public void operation() {
for (Component child : children) {
child.operation();
}
}
public void add(Component c) {
children.add(c);
}
public void remove(Component c) {
children.remove(c);
}
public Component getChild(int t) {
return children.get(t);
}
}
/**
* @description: 树叶节点
* @author: wjw
* @date: 2022/4/3
*/
public class Leaf implements Component{
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void operation() {
System.out.println("我是树叶节点:" + name);
}
}
/**
* @description: 客户端类
* @author: wjw
* @date: 2022/4/3
*/
public class Client {
public static void main(String[] args) {
Composite composite = new Composite();
Leaf leaf1 = new Leaf("1");
Leaf leaf2 = new Leaf("2");
composite.add(leaf1);
composite.add(leaf2);
composite.operation();
}
}
客户端测试结果:
我是树叶节点:1
我是树叶节点:2
组合模式常见的应用场景主要是出现树形结构的地方,比如文件目录,公司人员架构图等等
比如按照部门和员工组织成树形结构,可以统一处理薪资:
/**
* @description: 人力资源抽象构件
* @author: wjw
* @date: 2022/4/3
*/
public abstract class HumanResource {
protected long id;
protected double salary;
public HumanResource(long id) {
this.id = id;
}
public long getId() {
return id;
}
/**
* 计算工资
* @return 工资结果
*/
public abstract double calculateSalary();
}
/**
* @description: 部门树枝构件
* @author: wjw
* @date: 2022/4/3
*/
public class Department extends HumanResource{
private List<HumanResource> humanResources = new ArrayList<>();
public Department(long id) {
super(id);
}
@Override
public double calculateSalary() {
double totalSalary = 0;
for (HumanResource humanResource : humanResources) {
totalSalary += humanResource.calculateSalary();
}
this.salary = totalSalary;
return totalSalary;
}
public void addHumanResource(HumanResource humanResource) {
humanResources.add(humanResource);
}
}
/**
* @description: 员工树叶构件
* @author: wjw
* @date: 2022/4/3
*/
public class Employee extends HumanResource{
public Employee(long id, double salary) {
super(id);
this.salary = salary;
}
@Override
public double calculateSalary() {
return salary;
}
}
《设计模式之美》
http://c.biancheng.net/view/1373.html
《Java 设计模式》
《设计模式:可复用面向对象软件的基础》
我正在通过 labrepl 工作,我看到了一些遵循此模式的代码: ;; Pattern (apply #(apply f %&) coll) ;; Concrete example user=> (a
我从未向应用商店提交过应用,但我会在不久的将来提交。 到目前为止,我对为 iPhone 而非 iPad 进行设计感到很自在。 我了解,通过将通用PAID 应用放到应用商店,客户只需支付一次就可以同时使
我有一个应用程序,它使用不同的 Facebook 应用程序(2 个不同的 AppID)在 Facebook 上发布并显示它是“通过 iPhone”/“通过 iPad”。 当 Facebook 应用程序
我有一个要求,我们必须通过将网站源文件保存在本地 iOS 应用程序中来在 iOS 应用程序 Webview 中运行网站。 Angular 需要服务器来运行应用程序,但由于我们将文件保存在本地,我们无法
所以我有一个单页客户端应用程序。 正常流程: 应用程序 -> OAuth2 服务器 -> 应用程序 我们有自己的 OAuth2 服务器,因此人们可以登录应用程序并获取与用户实体关联的 access_t
假设我有一个安装在用户设备上的 Android 应用程序 A,我的应用程序有一个 AppWidget,我们可以让其他 Android 开发人员在其中以每次安装成本为基础发布他们的应用程序推广广告。因此
Secrets of the JavaScript Ninja中有一个例子它提供了以下代码来绕过 JavaScript 的 Math.min() 函数,该函数需要一个可变长度列表。 Example:
当我分别将数组和对象传递给 function.apply() 时,我得到 NaN 的 o/p,但是当我传递对象和数组时,我得到一个数字。为什么会发生这种情况? 由于数组也被视为对象,为什么我无法使用它
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界. 这篇CFSDN的博客文章ASP转换格林威治时间函数DateDiff()应用由作者收集整理,如果你
我正在将列表传递给 map并且想要返回一个带有合并名称的 data.frame 对象。 例如: library(tidyverse) library(broom) mtcars %>% spl
我有一个非常基本的问题,但我不知道如何实现它:我有一个返回数据框,其中每个工具的返回值是按行排列的: tmp<-as.data.frame(t(data.frame(a=rnorm(250,0,1)
我正在使用我的 FB 应用创建群组并邀请用户加入我的应用群组,第一次一切正常。当我尝试创建另一个组时,出现以下错误: {"(OAuthException - #4009) (#4009) 在有更多用户
我们正在开发一款类似于“会说话的本”应用程序的 child 应用程序。它包含大量用于交互式动画的 JPEG 图像序列。 问题是动画在 iPad Air 上播放正常,但在 iPad 2 上播放缓慢或滞后
我关注 clojure 一段时间了,它的一些功能非常令人兴奋(持久数据结构、函数式方法、不可变状态)。然而,由于我仍在学习,我想了解如何在实际场景中应用,证明其好处,然后演化并应用于更复杂的问题。即,
我开发了一个仅使用挪威语的应用程序。该应用程序不使用本地化,因为它应该仅以一种语言(挪威语)显示。但是,我已在 Info.plist 文件中将“本地化 native 开发区域”设置为“no”。我还使用
读完 Anthony's response 后上a style-related parser question ,我试图说服自己编写单体解析器仍然可以相当紧凑。 所以而不是 reference ::
multicore 库中是否有类似 sapply 的东西?还是我必须 unlist(mclapply(..)) 才能实现这一点? 如果它不存在:推理是什么? 提前致谢,如果这是一个愚蠢的问题,我们深表
我喜欢在窗口中弹出结果,以便更容易查看和查找(例如,它们不会随着控制台继续滚动而丢失)。一种方法是使用 sink() 和 file.show()。例如: y <- rnorm(100); x <- r
我有一个如下所示的 spring mvc Controller @RequestMapping(value="/new", method=RequestMethod.POST) public Stri
我正在阅读 StructureMap关于依赖注入(inject),首先有两部分初始化映射,具体类类型的接口(interface),另一部分只是实例化(请求实例)。 第一部分需要配置和设置,这是在 Bo
我是一名优秀的程序员,十分优秀!