#ifndef __COMPOSITE_H__
#define __COMPOSITE_H__
#include <sstream>
#include <string>
#include <list>
//【说明】
// 组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。
// 同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。
//【定义】
// 组合模式(Composite) :将对象组合成树形结构以表示“部分-整体”的层次结构,组合使得用户对单个对象和组合对象的使用具有一致性。
//【角色】
// Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口。
// Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了抽象构件中定义的接口。
// Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点。
//【意义】
//如果不使用组合模式,客户端代码将过多地依赖于容器对象复杂的内部实现结构,容器对象内部实现结构的变化将引起客户代码的频繁变化,带来了代码维护复杂、可扩展性差等弊端。
//组合模式通常可用来表示树形结构,这种结构随处可见,如公司里的部门结构,计算机里的目录结构等。
//【示例】
//目录条目,抽象出容器和内容的一致接口
class Entry
{
public:
Entry(){ }
virtual ~Entry(){ }
public:
virtual std::string GetName() = 0;
virtual int GetSize() = 0;
virtual Entry * Add(Entry * entry); //不定义为纯虚函数,放在Entry里实现,则可以在File中不实现该方法
virtual void PrintList(const std::string& prefix) = 0;
};
//文件
class File : public Entry
{
public:
File(const std::string& name, int size) : m_name(name), m_size(size){ }
~File(){ }
public:
virtual std::string GetName();
virtual int GetSize();
virtual void PrintList(const std::string& prefix);
private:
std::string m_name;
int m_size;
};
//目录,维护一个目录条目列表
class Directoty : public Entry
{
public:
Directoty(const std::string& name);
~Directoty();
public:
virtual std::string GetName();
virtual int GetSize();
virtual Entry * Add(Entry * entry);
virtual void PrintList(const std::string& prefix);
private:
std::string m_name;
std::list<Entry *> m_list;
};
void TestComposite();
#endif
#include "Composite.h"
Entry * Entry::Add(Entry * entry)
{
return NULL;
}
std::string File::GetName()
{
return m_name;
}
int File::GetSize()
{
return m_size;
}
void File::PrintList(const std::string& prefix)
{
printf("%s/%s \n", prefix.c_str(), m_name.c_str());
}
Directoty::Directoty(const std::string& name) : m_name(name)
{
}
Directoty::~Directoty()
{
std::list<Entry *>::iterator iter = m_list.begin();
for ( ; iter != m_list.end(); iter++)
{
if (*iter)
{
delete *iter;
*iter = NULL;
}
}
}
std::string Directoty::GetName()
{
return m_name;
}
int Directoty::GetSize()
{
int size = 0;
std::list<Entry *>::iterator iter = m_list.begin();
for (; iter != m_list.end(); iter++)
{
Entry * entry = * iter;
size += entry->GetSize();
}
return size;
}
Entry * Directoty::Add(Entry * entry)
{
m_list.push_back(entry);
return entry;
}
void Directoty::PrintList(const std::string& prefix)
{
printf("%s/%s \n", prefix.c_str(), m_name.c_str());
std::string newprefix = prefix + "/" + m_name;
std::list<Entry *>::iterator iter = m_list.begin();
for (; iter != m_list.end(); iter++)
{
Entry * entry = * iter;
entry->PrintList(newprefix);
}
}
void TestComposite()
{
Entry * rootdir = new Directoty("root");
Entry * bindir = new Directoty("bin");
Entry * usrdir = new Directoty("usr");
rootdir->Add(bindir);
rootdir->Add(usrdir);
bindir->Add(new File("vi",1000));
bindir->Add(new File("ls",500));
Entry * tom = new Directoty("Tom");
usrdir->Add(tom);
usrdir->Add(new File("mm.txt",123));
tom->Add(new File("abc.txt",200));
rootdir->PrintList("");
delete rootdir;
}