您的位置:首页 > 编程语言 > Java开发

Java设计模式之合成模式

2018-01-13 17:39 393 查看
合成模式(composite pattern): 允许你将对象组合成树形结构来表现”整体/部分”层次结构. 合成模式能让客户以一致的方式处理个别对象以及对象组合.

合成模式的实现根据所实现接口的区别分为两种形式:安全式和透明式

安全式合成模式的详解

类图:



角色说明:

抽象构件角色(Component):这是一个抽象角色,它给参加组合的对象定义出公共的接口及其默认行为,可以用来管理所有的子对象。合成对象通常把它所包含的子对象当做类型为Component的对象。在安全式的合成模式里,构件角色并不定义出管理子对象的方法,这一定义由数字构件对象给出。

叶子构件角色(Leaf):叶子对象是没有下级子对象的对象,定义出参加组合的原始对象行为。

树枝构件角色(Composite):代表参加组合的又下级子对象的对象,树枝构件类给出所有的管理子对象的方法,如add()、remove()和getChild()。

代码演示,抽象构件类:

public interface Component {
// 输出结构的名称
public void showStructure(String str);
}


树枝构件类:

public class Composite implements Component {
// 用来存储合成对象中的子构件对象
private List<Component> childComponents = new ArrayList<>();
// 合成对象的名称
private String name;

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

/**
* 增加一个子构件对象
*
* @param child
*/
public void addChild(Component child) {
childComponents.add(child);
}

/**
* 移除一个子构件对象
*
* @param index
*/
public void removeChild(int index) {
childComponents.remove(index);
}

// 获取所有子构件对象
public List<Component> getChild() {
return childComponents;
}

/**
* 输出结构的名称
*/
@Override
public void showStructure(String str) {
// 首先输出最高级构件
System.out.println(str + "●" + this.name);
// 如果含有子构件,则输出
if (this.childComponents != null) {
// 子构件向后缩进显示
str += "   ";
// 输出当前对象的子构件对象
for (Component c : childComponents) {
// 递归输出每个子对象
c.showStructure(str);
}
}

}

}


叶子对象类:

public class Leaf implements Component {
// 叶子对象的名称
private String name;

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

/**
* 输出叶子构件的对象,叶子已经是最低级构件,所以只显示叶子名称就行
*/
@Override
public void showStructure(String str) {
str += "   ";
System.out.println(str + "〉" + name);
}

}


测试类:

public class Client {
public static void main(String[] args) {
//声明最高级构件
Composite root = new Composite("宠物");
//子构件
Composite dog = new Composite("宠物狗");
Composite cat = new Composite("宠物猫");

//添加子构件
root.addChild(dog);
root.addChild(cat);

//声明叶子对象
Leaf leaf1 = new Leaf("柴犬");
Leaf leaf2 = new Leaf("二哈");

//添加叶子对象
dog.addChild(leaf1);
dog.addChild(leaf2);

Leaf leaf3 = new Leaf("波斯猫");
Leaf leaf4 = new Leaf("咖菲猫");
Leaf leaf5 = new Leaf("机器猫");

cat.addChild(leaf3);
cat.addChild(leaf4);
cat.addChild(leaf5);

root.showStructure("");

System.out.println("====================");
//移除不是动物的猫
cat.removeChild(2);
root.showStructure("");

}
}


运行结果:



从类图和代码可以看出树枝构件类Composite都实现了addChild()、removeChild()和getChild()的方法,而叶子构件类则没有。这是安全式合成模式的特点,因为这个特点,客户端不可能调用到叶子构件类的这些方法,因为叶子构件类根本没有这些方法。

透明式合成模式的详解

类图:



代码演示,抽象构件类:

public abstract class Component {
// 输出构件的名称
public abstract void showStructure(String str);

/**
* 增加一个子构件对象
*
* @param child
*/
public void addChild(Component child) {

// 叶子构件类没有此功能,若缺省实现,则抛出异常
throw new UnsupportedOperationException("对象不支持此操作");
}

/**
* 移除一个子构件对象
*
* @param index
*/
public void removeChild(int index) {

// 叶子构件类没有此功能,若缺省实现,则抛出异常
throw new UnsupportedOperationException("对象不支持此操作");
}

// 获取所有子构件对象
public List<Component> getChild() {

// 叶子构件类没有此功能,若缺省实现,则抛出异常
throw new UnsupportedOperationException("对象不支持此操作");
}
}


树枝构件类:

public class Composite extends Component {
// 用来存储合成对象中的子构件对象
private List<Component> childComponents = new ArrayList<>();
// 合成对象的名称
private String name;

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

/**
* 增加一个子构件对象
*
* @param child
*/
@Override
public void addChild(Component child) {
childComponents.add(child);
}

/**
* 移除一个子构件对象
*
* @param index
*/
@Override
public void removeChild(int index) {
childComponents.remove(index);
}

// 获取所有子构件对象
@Override
public List<Component> getChild() {
return childComponents;
}

/**
* 输出结构的名称
*/
@Override
public void showStructure(String str) {
// 首先输出最高级构件
System.out.println(str + "●" + this.name);
// 如果含有子构件,则输出
if (this.childComponents != null) {
// 子构件向后缩进显示
str += "   ";
// 输出当前对象的子构件对象
for (Component c : childComponents) {
// 递归输出每个子对象
c.showStructure(str);
}
}

}

}


叶子构件类:

public class Leaf extends Component {
// 叶子对象的名称
private String name;

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

/**
* 输出叶子构件的对象,叶子已经是最低级构件,所以只显示叶子名称就行
*/
@Override
public void showStructure(String str) {
str += "   ";
System.out.println(str + "〉" + name);
}

}


测试类:

public class Client {
public static void main(String[] args) {
//声明最高级构件
Component root = new Composite("宠物");
//子构件
Component dog = new Composite("宠物狗");
Component cat = new Composite("宠物猫");

//添加子构件
root.addChild(dog);
root.addChild(cat);

//声明叶子对象,这时不再区分Composite或Leaf对象了
Component leaf1 = new Leaf("柴犬");
Component leaf2 = new Leaf("二哈");

//添加叶子对象
dog.addChild(leaf1);
dog.addChild(leaf2);

Component leaf3 = new Leaf("波斯猫");
Component leaf4 = new Leaf("咖菲猫");
Component leaf5 = new Leaf("机器猫");

cat.addChild(leaf3);
cat.addChild(leaf4);
cat.addChild(leaf5);

root.showStructure("");

System.out.println("====================");
//移除不是动物的猫
cat.removeChild(2);
root.showStructure("");

}
}


运行结果跟安全式的一样:



合成模式的安全式和透明式的选择

安全式:从客户端使用上看,安全式就不会发生误操作的可能。

透明式:从客户端使用上看,透明式是不用区分树枝对象和叶子对象。

合成模式的目的是让客户端不区分操作的是树枝对象还是叶子对象,而是统一的方式来操作。还有,对于安全式的实现,区分树枝和叶子对象的情况下,有时需要类型强转,这种体现就不安全了。所以综合考虑还是着重选择透明式合成模式的实现。当然这不是绝对的,还是要看具体需求的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息