温故而知新:设计模式之组合模式(Composite)
时间:2022-04-23
本文章向大家介绍温故而知新:设计模式之组合模式(Composite),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
场景:
如果想模拟windows的开始菜单,分析一下会发现里面的菜单项:有些有子菜单,有些则没有;因此大体可以将菜单类分为二类,设计代码如下:
/// <summary>
/// 菜单的显示接口
/// </summary>
public interface IMenu
{
void Show();
}
/// <summary>
/// 菜单基类
/// </summary>
public class MenuBase
{
public string MenuName { set; get; }
}
/// <summary>
/// 有子菜单的菜单类
/// </summary>
public class Menu : MenuBase, IMenu
{
public void Show()
{
Console.WriteLine(MenuName);
}
private IList<IMenu> _children;
public IList<IMenu> Children
{
get
{
if (_children == null)
{
_children = new List<IMenu>();
}
return _children;
}
}
}
/// <summary>
/// 无子菜单的菜单类(即最底级菜单)
/// </summary>
public class SingleMenu : MenuBase, IMenu
{
public void Show()
{
Console.WriteLine( MenuName);
}
}
客户端示例调用如下:
class Program
{
//客户程序
static void Main(string[] args)
{
Menu menuContainer = new Menu() { MenuName = "开始" };
SingleMenu menuShutdown = new SingleMenu() { MenuName = "t关机" };
Menu menuProgram = new Menu() { MenuName = "t程序" };
SingleMenu menuStartUp = new SingleMenu() { MenuName = "tt启动" };
menuProgram.Children.Add(menuStartUp);
menuContainer.Children.Add(menuProgram);
menuContainer.Children.Add(menuShutdown);
menuContainer.Show();
foreach (IMenu item in menuContainer.Children)
{
if (item is SingleMenu)
{
item.Show();
}
else if (item is Menu)
{
ShowAllSubMenu(item);
}
}
Console.ReadLine();
}
/// <summary>
/// 客户端调用的递归Show程序
/// </summary>
/// <param name="menu"></param>
static void ShowAllSubMenu(IMenu menu)
{
if (menu is SingleMenu)
{
menu.Show();
}
else if (menu is Menu)
{
menu.Show();
IList<IMenu> children = (menu as Menu).Children;
foreach (IMenu i in children)
{
ShowAllSubMenu(i);
}
}
}
}
从功能正确性上讲,上面的示意代码并无大错,但是如果从客户程序上考虑,却发现这样并非最佳实践:客户程序依赖了太多的Menu类细节,客户程序在树型菜单创建完成后,最关心的莫过于如何把菜单完整的显示出来,但上面的代码中为了达到这个目的,却不得不知道子菜单的内部实现(通过Children和类型判断),如果以后菜单类升级,修改了内部构造(比如将Children改成GetChildren),客户程序将被迫重新修改,这时候组合(Composite)模式就派上用场了。
using System;
using System.Collections.Generic;
namespace composite
{
class Program
{
//客户程序
static void Main(string[] args)
{
IMenu menuContainer = new Menu() { MenuName = "开始" };
IMenu menuShutdown = new SingleMenu() { MenuName = "t关机" };
IMenu menuProgram = new Menu() { MenuName = "t程序" };
IMenu menuStartUp = new SingleMenu() { MenuName = "tt启动" };
menuProgram.Add(menuStartUp);
menuContainer.Add(menuProgram);
menuContainer.Add(menuShutdown);
menuContainer.Show();
Console.ReadLine();
}
}
/// <summary>
/// 菜单的显示接口
/// </summary>
public interface IMenu
{
void Show();
void Add(IMenu menu);
void Remove(IMenu menu);
}
/// <summary>
/// 菜单基类
/// </summary>
public abstract class MenuBase
{
public string MenuName { set; get; }
protected IList<IMenu> Children;
}
/// <summary>
/// 有子菜单的菜单类
/// </summary>
public class Menu : MenuBase,IMenu
{
public void Show()
{
ShowAllSubMenu(this);
}
public void ShowAllSubMenu(IMenu menu)
{
if (menu is SingleMenu)
{
menu.Show();
}
else if (menu is Menu)
{
Console.WriteLine((menu as Menu).MenuName);
IList<IMenu> children = (menu as Menu).Children;
foreach (IMenu i in children)
{
ShowAllSubMenu(i);
}
}
}
public void Add(IMenu menu)
{
if (Children == null) { Children = new List<IMenu>(); }
Children.Add(menu);
}
public void Remove(IMenu menu)
{
if (Children == null) { Children = new List<IMenu>(); }
Children.Add(menu);
}
}
/// <summary>
/// 无子菜单的菜单类(即最底级菜单)
/// </summary>
public class SingleMenu :MenuBase, IMenu
{
public void Show()
{
Console.WriteLine( MenuName);
}
public void Add(IMenu menu)
{
throw new Exception("最底层菜单无法Add子元素!");
}
public void Remove(IMenu menu)
{
throw new Exception("最底层菜单无法Remove子元素!");
}
}
}
最后再来理解Composite的意图可能就更清楚了(摘自terrylee的“.NET设计模式(11):组合模式(Composite Pattern)"): 概述 组合模式有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解 耦。 意图 将对象组合成树形结构以表示“部分-整体”的层次结构。Composite模式使得用户对单个对象和组合对象的使用具有一致性。[GOF 《设计模式》]
类图:
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法