设计模式与代码结构分析
设计模式与代码结构
〇,设计模式简介
“设计模式”这个概念最早来源于建筑领域,在90年代后被引入软件工程领域。
软件设计模式,又称设计模式,又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。
一,设计模式要素、原则与分类
软件设计模式使人们可以更加简单方便地复用成功的设计和体系结构,它通常包含以下几个基本要素:模式名称、别名、动机、问题、解决方案、效果、结构、模式角色、合作关系、实现方法、适用性、已知应用、例程、模式扩展和相关模式等。
设计模式中还有如下的设计原则:
里氏替换原则:子类可以扩展父类的功能,但不能改变父类原有的功能
依赖倒置原则:通过要面向接口的编程来降低类间的耦合性
单一职责原则:对象(类)不应该承担太多职责
接口隔离原则:将臃肿庞大的接口拆分成更小的和更具体的接口
迪米特法则:只与你的直接朋友交谈,不跟“陌生人”说话
合成复用原则:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现
- 外观(Facade)角色:为多个子系统对外提供一个共同的接口。
- 子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。
- 客户(Client)角色:通过一个外观角色访问各个子系统的功能。
// 观察者基类 class Observer_base { public: virtual ~Observer_base() {} // 显示名字 virtual const string get_name() const = 0; // 更新 virtual void update(const string & words) = 0; // 重载==运算符,从订阅列表删除元素的时候使用 virtual bool operator == (const Observer_base* outer) const = 0; }; // 被观察者基类 class Target_base{ public: virtual ~Target_base() {} // 添加订阅者 virtual void add_one_follower(Observer_base* outer) = 0; // 删除订阅者 virtual void rm_one_follower(Observer_base* outer) = 0; // 更新发布内容,即本类中的words变量 virtual void set_string(const string& words) = 0; };
// 被观察者的一个具体类,比如某队比分推送 class Target_scorePush: public Target_base { private: // 观察者集合 set<Observer_base*> followers; // 被观察者发布的内容 string words; public: // 添加订阅者 void add_one_follower(Observer_base* outer) { followers.insert(outer); cout << outer->get_name() << "成功订阅!" << endl; } // 删除订阅者 void rm_one_follower(Observer_base* outer) { set<Observer_base*>::iterator it; for ( it = followers.begin(); it != followers.end(); ++it) { if (**it == outer) { followers.erase(it); cout << outer->get_name() << "删除成功!" << endl; break; } cout << outer->get_name() <<"删除失败,预删除用户未在订阅列表中。" << endl; } } // 发布新的内容 void set_string(const string& words) { // 更新内容 this->words = words; cout << "巴萨最新比分推送: " << this->words << endl; // 通知订阅者,即调用订阅者的update函数 set<Observer_base*>::iterator it; for (it = followers.begin(); it != followers.end(); ++it) { (*it)->update(this->words); } } }; // 观察者的一个实例,比如一个球迷 class Observer_barcaFans :public Observer_base{ private: string name; string news; public: // 构造函数 Observer_barcaFans(const string& name) :name(name) {} // 更新消息 void update(const string& words){ this->news = words; cout << "用户" << name << "你好! 巴萨的最新比分是: " << news << endl; } // 获取球迷名字 const string get_name() const { return this->name; } // 运算符重载 bool operator == (const Observer_base* outer) const { return outer->get_name() == this->name; } };
int main() { // 创建一个比分推送 Target_base* scorePush_liu = new Target_scorePush(); // 创建两个球迷 Observer_base* li_ming = new Observer_barcaFans("李明"); Observer_base* xiao_hong = new Observer_barcaFans("小红"); // 进行订阅 scorePush_liu->add_one_follower(li_ming); scorePush_liu->add_one_follower(xiao_hong); // 推送比分 scorePush_liu->set_string("巴萨 1 : 0 马洛卡 \n特狮助攻,格子小角度挑射破门!\n"); scorePush_liu->set_string("巴萨 2 : 0 马洛卡 \n常规操作,梅西禁区外远射破门。\n"); scorePush_liu->set_string("巴萨 2 : 1 马洛卡 \n呵呵。\n"); scorePush_liu->set_string("巴萨 3 : 1 马洛卡 \n复制粘贴!梅西禁区外远射破门。\n"); scorePush_liu->set_string("巴萨 4 : 1 马洛卡 \n德容直塞,苏神脚跟画彩虹!巧射破门。\n"); scorePush_liu->set_string("巴萨 4 : 2 马洛卡 \n呵呵,还敢还手。\n"); scorePush_liu->set_string("巴萨 5 : 2 马洛卡 \n苏神回做,梅西搓射洞穿人墙,手捧金球头带帽!\n"); scorePush_liu->set_string("全场比赛结束,巴萨 5 : 2 马洛卡 \nps:巴尔韦德下课!\n"); delete scorePush_liu; delete li_ming; delete xiao_hong; return 0; }
代码的实现结果如下:
- 对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易。通过引入外观模式,客户代码将变得很简单,与之关联的对象也很少。
- 实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。
- 降低了大型软件系统中的编译依赖性,并简化了系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
- 只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。
同时,外观模式还有如下缺点:
- 不能很好地限制客户使用子系统类,如果对客户访问子系统类做太多的限制则减少了可变性和灵活性。
- 在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
5,总结
在外观模式中,外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。
外观模式包含两个角色:外观角色是在客户端直接调用的角色,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理;在软件系统中可以同时有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能。
外观模式要求一个子系统的外部与其内部的通信通过一个统一的外观对象进行,外观类将客户端与子系统的内部复杂性分隔开,使得客户端只需要与外观对象打交道,而不需要与子系统内部的很多对象打交道。
外观模式主要优点在于对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易,它实现了子系统与客户之间的松耦合关系,并降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程;其缺点在于不能很好地限制客户使用子系统类,而且在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”。
外观模式适用情况包括:要为一个复杂子系统提供一个简单接口;客户程序与多个子系统之间存在很大的依赖性;在层次化结构中,需要定义系统中每一层的入口,使得层与层之间不直接产生联系。