首页 文章 精选 留言 我的

精选列表

搜索[c/c ],共10000篇文章
优秀的个人博客,低调大师

C++桥接模式

简述 桥接模式(Bridge Pattern)是将抽象部分与它的实现部分分离,使它们都可以独立地变化。 简述 模式结构 优缺点 适用场景 案例分析 代码实现 版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820 模式结构 UML 结构图: Abstraction(抽象类):用于定义抽象类的接口,并且维护一个指向 Implementor 实现类的指针。它与 Implementor 之间具有关联关系。 RefinedAbstraction(扩充抽象类):扩充由 Abstraction 定义的接口,在 RefinedAbstraction 中可以调用在 Implementor 中定义的业务方法。 Implementor(实现类接口):定义实现类的接口,这个接口不一定要与 Abstraction 的接口完全一致,事实上这两个接口可以完全不同。 ConcreteImplementor(具体实现类):实现了 Implementor 定义的接口,在不同的 ConcreteImplementor 中提供基本操作的不同实现。在程序运行时,ConcreteImplementor 对象将替换其父类对象,提供给 Abstraction 具体的业务操作方法。 优缺点 优点: 分离抽象和实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,也就是说抽象和实现不再在同一个继承层次结构中,而是“子类化”它们,使它们各自都具有自己的子类,以便任何组合子类,从而获得多维度组合对象。 在很多情况下,桥接模式可以取代多层继承方案,多层继承方案违背了“单一职责原则”,复用性较差,且类的个数非常多,桥接模式是比多层继承方案更好的解决方法,它极大减少了子类的个数。 桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统,符合“开闭原则”。 缺点: 桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。 适用场景 如果一个系统需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。 “抽象部分”和“实现部分”可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。 一个系统存在多个(≥ 2)独立变化的维度,且这多个维度都需要独立进行扩展。 对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。 案例分析 开关和电器 电器是现代生活必不可少的东西,几乎每家每户都有,电视、风扇、电灯。。。无论什么电器,都由开关控制。开关种类众多,有拉链式开关、两位开关、调光开关。。。 不管任何时候,都可以在不触及其它东西的情况下更换设备。例如,可以在不更换开关的情况下换掉灯泡,也可以在不接触灯泡或风扇的情况下更换开关,甚至可以在不接触开关的情况下将灯泡和风扇互换。 这看起来很自然,当然也应该这样!当不同的事物联系到一起时,它们应该在一个可以变更或者替换的系统中,以便不相互影响或者影响尽可能的小,这样才能更方便、更低成本地去管理系统。想象一下,如果要换房间里的一个灯泡,得要求把开关也换了,你会考虑使用这样的系统吗? 代码实现 创建实现类接口 所有电器都有一些共性,可以被打开和关闭: // implementor.h #ifndef IMPLEMENTOR_H #define IMPLEMENTOR_H // 电器 class IElectricalEquipment { public: virtual ~IElectricalEquipment() {} // 打开 virtual void PowerOn() = 0; // 关闭 virtual void PowerOff() = 0; }; #endif // IMPLEMENTOR_H 创建具体实现类 接下来,是真正的电器 - 电灯和风扇,它们实现了 IElectricalEquipment 接口: // concrete_implementor.h #ifndef CONCRETE_IMPLEMENTOR_H #define CONCRETE_IMPLEMENTOR_H #include "implementor.h" #include <iostream> // 电灯 class Light : public IElectricalEquipment { public: // 开灯 virtual void PowerOn() override { std::cout << "Light is on." << std::endl; } // 关灯 virtual void PowerOff() override { std::cout << "Light is off." << std::endl; } }; // 风扇 class Fan : public IElectricalEquipment { public: // 打开风扇 virtual void PowerOn() override { std::cout << "Fan is on." << std::endl; } // 关闭风扇 virtual void PowerOff() override { std::cout << "Fan is off." << std::endl; } }; #endif // CONCRETE_IMPLEMENTOR_H 创建抽象类 对于开关来说,它并不知道电灯和风扇的存在,只知道自己可以控制(打开/关闭)某个电器。也就是说,每个 ISwitch 应该持有一个 IElectricalEquipment 对象: // abstraction.h #ifndef ABSTRACTION_H #define ABSTRACTION_H #include "implementor.h" // 开关 class ISwitch { public: ISwitch(IElectricalEquipment *ee) { m_pEe = ee;} virtual ~ISwitch() {} // 打开电器 virtual void On() = 0; // 关闭电器 virtual void Off() = 0; protected: IElectricalEquipment *m_pEe; }; #endif // ABSTRACTION_H 创建扩充抽象类 特定类型的开关很多,比如拉链式开关、两位开关: // refined_abstraction.h #ifndef REFINED_ABSTRACTION_H #define REFINED_ABSTRACTION_H #include "abstraction.h" #include <iostream> // 拉链式开关 class PullChainSwitch : public ISwitch { public: PullChainSwitch(IElectricalEquipment *ee) : ISwitch(ee) {} // 用拉链式开关打开电器 virtual void On() override { std::cout << "Switch on the equipment with a pull chain switch." << std::endl; m_pEe->PowerOn(); } // 用拉链式开关关闭电器 virtual void Off() override { std::cout << "Switch off the equipment with a pull chain switch." << std::endl; m_pEe->PowerOff(); } }; // 两位开关 class TwoPositionSwitch : public ISwitch { public: TwoPositionSwitch(IElectricalEquipment *ee) : ISwitch(ee) {} // 用两位开关打开电器 virtual void On() override { std::cout << "Switch on the equipment with a two-position switch." << std::endl; m_pEe->PowerOn(); } // 用两位开关关闭电器 virtual void Off() override { std::cout << "Switch off the equipment with a two-position switch." << std::endl; m_pEe->PowerOff(); } }; #endif // REFINED_ABSTRACTION_H 创建客户端 很好,是时候将开关和电器关联起来了: // main.cpp #include "refined_abstraction.h" #include "concrete_implementor.h" #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} } #endif int main() { // 创建电器 - 电灯、风扇 IElectricalEquipment *light = new Light(); IElectricalEquipment *fan = new Fan(); /** * 创建开关 - 拉链式开关、两位开关 * 将拉链式开关和电灯关联起来,将两位开关和风扇关联起来 **/ ISwitch *pullChain = new PullChainSwitch(light); ISwitch *twoPosition= new TwoPositionSwitch(fan); // 开灯、关灯 pullChain->On(); pullChain->Off(); // 打开风扇、关闭风扇 twoPosition->On(); twoPosition->Off(); SAFE_DELETE(twoPosition); SAFE_DELETE(pullChain); SAFE_DELETE(fan); SAFE_DELETE(light); getchar(); return 0; } 输出如下: Switch on the equipment with a pull chain switch. Light is on. Switch off the equipment with a pull chain switch. Light is off. Switch on the equipment with a two-position switch. Fan is on. Switch off the equipment with a two-position switch. Fan is off.

优秀的个人博客,低调大师

C++模版方法模式

简述 模版方法模式(Template Method Pattern)定义一个操作中算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 简述 模式结构 优缺点 适用场景 案例分析 代码实现 版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820 模式结构 UML 结构图: 抽象类(AbstractClass):定义抽象的原语操作,具体的子类将重定义它们以实现一个算法的各步骤。主要是实现一个模板方法,定义一个算法的骨架。该模板方法不仅调用原语操作,也调用定义在 AbstractClass 或其他对象中的操作。 具体类(ConcreteClass):实现原语操作以完成算法中与特定子类相关的步骤。 优缺点 优点: 在父类中形式化地定义一个算法,而由其子类实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。 模板方法模式是一种代码复用技术,在类库设计中尤为重要,它提取了类库中的公共行为,将公共行为放在父类中,而通过其子类来实现不同的行为,它鼓励我们恰当使用继承来实现代码复用。 可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行。 在模板方法模式中,可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则。 缺点: 需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加,系统更加庞大,设计也更加抽象,此时,可结合桥接模式来进行设计。 适用场景 对一些复杂的算法进行分割,将算法中固定不变的部分设计为模板方法和父类具体方法,而一些可变的细节由子类实现。 各子类中公共的行为应被提取出来并集中到一个公共父类中,以避免代码重复。 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。 案例分析 招聘流程 谈及校招,对学生们而言,最诱人的名字无疑是 BAT,工资高、福利好,而且还能学到很多前沿的技术!当然,巨头公司的 Offer 不是那么容易拿的,不仅要成绩优异,更要技术过人。 无论什么公司,在校招时一般都会采用“宣讲会 -> 接收简历 -> 面试 -> 发放 Offer”这样一套固定流程。其中,各公司宣讲会(宣传企业文化、福利待遇)和接收简历(自带简历)的形式几乎是一样的,不同的是面试和发放 Offer 环节。阿里需要经过一面、二面、三面,并提供30W/年的薪酬;而腾讯则需要一面、二面,并提供25W/年的薪酬。 这里,公司是抽象类,“宣讲会 -> 接收简历 -> 面试 -> 发放 Offer”则是一套固定的模板方法(招聘流程)。具体类由阿里和腾讯表示,不同之处在于面试和发放 Offer 环节,需要它们分别实现。 代码实现 创建抽象类 抽象类由 Company 表示,它提供了一套固定的模板方法 Recruit(),用于标准化算法的骨架: // abstract_class.h #ifndef ABSTRACT_CLASS_H #define ABSTRACT_CLASS_H #include <iostream> // 公司 class Company { public: virtual ~Company() {} // 校园招聘 void Recruit() { std::cout << "---------- Begin ----------" << std::endl; CareerTalk(); ReceiveResume(); Interview(); Offer(); std::cout << "---------- End ----------" << std::endl; } // 宣讲会 void CareerTalk() { std::cout << "Delivery" << std::endl; } // 接收简历 void ReceiveResume() { std::cout << "Receive Resume" << std::endl; } // 面试 virtual void Interview() = 0; // 发放 Offer virtual void Offer() = 0; }; #endif // ABSTRACT_CLASS_H 注意: 相同的行为 CareerTalk() 和 ReceiveResume() 有默认实现,不同的行为 Interview() 和 Offer() 采用“占位符”方式,需要由具体公司来实现。 创建具体类 具体公司有两个 - Alibaba、Tencent,它们的面试、录用方式不同: // concrete_class.h #ifndef CONCRETE_CLASS_H #define CONCRETE_CLASS_H #include "abstract_class.h" #include <iostream> // 阿里 class Alibaba : public Company { public: virtual void Interview() override { std::cout << "First interview -> Second interview -> Third interview" << std::endl; } virtual void Offer() override { std::cout << "30W" << std::endl; } }; // 腾讯 class Tencent : public Company { public: virtual void Interview() override { std::cout << "First interview -> Second interview" << std::endl; } virtual void Offer() override { std::cout << "25W" << std::endl; } }; #endif // CONCRETE_CLASS_H 创建客户端 校招开启,Offer 快到碗里来: // main.cpp #include "concrete_class.h" #ifndef SAFE_DELETE #define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} } #endif int main() { // 阿里校招 Company *alibaba = new Alibaba(); alibaba->Recruit(); // 腾讯校招 Company *tencent = new Tencent(); tencent->Recruit(); SAFE_DELETE(tencent); SAFE_DELETE(alibaba); getchar(); return 0; } 输出如下: ———- Begin ———- Delivery Receive Resume First interview -> Second interview -> Third interview 30W ———- End ———- ———- Begin ———- Delivery Receive Resume First interview -> Second interview 25W ———- End ———-

优秀的个人博客,低调大师

C# 异步转同步

当我们的程序运行时,调用了一段异步的逻辑A,这段异步的逻辑无法转化为同步(如动画、下载进度等) 而,我们又需要等待异步逻辑A处理完成,然后再执行其它逻辑B。 那就迫切需要将异步转同步了! AutoResetEvent autoResetEvent = new AutoResetEvent(false) AutoResetEvent 可以在线程间发送信号互相通信,通过调用AWaitOne来等待信号,调用Set发送信息来启动已等待的线程。 很简单:一个await ,另一个set来唤醒。 AutoResetEvent autoResetEvent = new AutoResetEvent(false)--参数bool:若要将初始状态设置为终止,则为 true;若要将初始状态设置为非终止,则为 false await Task.Run(() => { autoResetEvent.WaitOne(); }); autoResetEvent.Set(); 比如: private async Task SetDelegateProgress() { var delegateProgress = new UIDelegateProgress(); delegateProgress.ProgressCompleted += () => { autoResetEvent.Set(); }; DelegateProgress = delegateProgress; await Task.Run(() => { autoResetEvent.WaitOne(); }); } 如上案例,当delegateProgress执行完后,通过AutoResetEvent 的方法Set来发送信息来唤醒子线程。 再如动画的同步等待处理: 1 /// <summary> 2 /// 执行动画 3 /// </summary> 4 /// <param name="storyboard"></param> 5 /// <returns></returns> 6 public static async Task ExecuteStoryboradAsync([NotNull] Storyboard storyboard) 7 { 8 if (storyboard == null) throw new ArgumentNullException(nameof(storyboard)); 9 10 AutoResetEvent autoResetEvent = new AutoResetEvent(false); 11 12 storyboard.Completed += OnStoryboardCompleted; 13 storyboard.Begin(); 14 15 void OnStoryboardCompleted(object sender, EventArgs e) 16 { 17 storyboard.Completed -= OnStoryboardCompleted; 18 autoResetEvent.Set(); 19 } 20 21 await Task.Run(() => { autoResetEvent.WaitOne(); }); 22 } 值得注意的是,WaitOne只能在子线程,如果放在主线程的话,会将整个线程终止(例如界面或者其它后台逻辑) AutoResetEvent可以在多个线程使用WaitOne来暂停线程,而暂停的线程则需要多次set来开启暂停的线程。 给你AutoResetEvent 类似的,还有一个ManualResetEvent。ManualResetEvent 是多个暂停线程,可以通过一次set直接开启全部暂停的线程。 ManualResetEvent与AutoResetEvent 不同的还有Reset方法,Reset与Set相反,为主动暂停线程。 详细ManualResetEvent & AutoResetEvent可参考:https://www.cnblogs.com/maitian-lf/p/3672390.html 关键字:动画同步,AutoResetEvent 作者: 唐宋元明清2188 出处: http://www.cnblogs.com/kybs0/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册