设计模式是一组模板,可简化软件开发过程,提升代码的质量和一致性。它们按类型分为:创建模式(处理对象创建)、行为模式(定义对象交互方式)和结构模式(用于组织类和对象)。本文重点讨论代理模式,一种结构模式,它充当其他对象的中介,提供统一的访问方式并允许灵活控制。代理模式尤其适用于分布式系统,允许客户端与远程服务交互,同时隐藏底层通信细节。
设计模式是软件架构师在一段时间内制定的一组模板。它们是软件程序员可以应用于自己的软件/应用程序开发的最佳实践。它们通过重用预先存在的解决方案节省时间和精力,同时提高代码的质量和一致性,从而提供了令人难以置信的优势。它还可以帮助增强与其他开发人员的沟通和协作,促进代码的适应和发展,并防止常见的陷阱和错误。总而言之,设计模式是简化编程过程的好方法。
广义上讲,有三种模式:结构模式,创建模式和行为模式。
创建模式与对象的创建有关,并将对象的创建与使用该对象的客户端分开。示例包括单例、工厂和工厂方法。
行为模式定义多个对象如何相互作用。命令模式、迭代器模式和观察者模式是一些常见的行为模式。这些模式展示了系统的不同组件如何相互行为和响应。它可以通过增强灵活性、模块化和可重用性来改进代码。
另一方面,结构模式处理类和对象的组成和组织。它可以通过将类和对象组合成更大的结构来隐藏系统的复杂性。示例包括适配器、复合、装饰器、外观和代理。
虽然设计模式是一种久经考验的解决方案,但它们是在良好的面向对象编程原则的基础上形成的。以下列出了一些关键原则:
针对接口进行编程:保持设计的灵活性。
确定软件中可能变化的部分,并将它们与变化的部分分开:保持设计模块化
倾向于组合而不是继承: 用单个对象组成大型结构。
松散耦合: 尽量减少对象的相互依赖。
开放/封闭原则: 类软件一旦代码完成、测试和验证,就应该对修改关闭,但该类可以通过继承的方式对扩展开放。
依赖反转:依赖于抽象或接口而不是类的具体实例。
单一责任原则: 一个类只负责一个需求。
示例:代理模式
我们选择了结构代理模式进行讨论。这是一种流行的模式,尤其在分布式系统中用作远程代理。顾名思义,代理模式是其他人的代理。代理设计的类提供面向公众的 API,客户端可以使用这些 API 发送请求。代理类具有访问真实对象服务的方法,并且可以在对来自客户端的请求进行身份验证之后向其提供请求。此外,代理模式可以允许延迟初始化。如果真实 对象的创建被认为是昂贵的,我们可以仅在客户端需要时延迟其实例化。它还允许日志记录和缓存,这些可以在代理类方法中实现。在分布式系统中,客户端和代理对象位于一个节点上,而为请求提供服务的实际对象位于另一个节点上,代理模式允许统一视图,客户端不知道哪个节点正在为该对象提供服务。
图 1:代理模式
图 1 显示了代理模式的架构图。它有一个包含ProxyObject句柄的客户端类。ProxyClass和RealClass 都派生自iProxy 接口类并实现 API。为了能够在两个节点之间进行通信,它们都另外有一个CommObject ,负责在网络上共享 时对命令和数据进行序列化和反序列化。代码片段提供了一组最小的类和方法声明,以直观地展示分布式系统如何协同运行。
// CommClass 提供序列化/反序列化 // 在分布式系统中,共享数据和命令 class CommClass { // RealClass 向 CommClass 注册一个回调来接收命令 // 以及来自代理的数据 <a style='color:#f60; text-decoration:underline;' href="https://www.php.cn/zt/58423.html" target="_blank">typedef</a> std::function<void(unsigned, vector<unsigned>)> fCallBack; public: CommClass() {} ~CommClass() {} // 代理类使用 CommClass 对象向远程服务发送命令和数据 void sendToRemoteService(unsigned cmd, std::vector<unsigned> data); // 远程服务类通过事件通知。它使用已注册的回调 // 调用远程服务 RealClass void receiveFromProxy(unsigned cmd, std::vector<unsigned> data) { _cb(cmd, data); } void registerCallBack(fCallBack cb) { _cb = cb; } private: fCallBack _cb; }; // 代理接口类声明面向公共的方法 class iProxy { public: iProxy() {} virtual ~iProxy() {} virtual void methodOne() = 0; virtual void methodTwo() = 0; }; // 实现接口类方法的具体类和 // 与客户端位于同一节点 class ProxyClass : public iProxy { public: ProxyClass() {}; ~ProxyClass() {}; // 实现接口 void methodOne() {}; void methodTwo() {}; private: CommClass CommObject; }; // 实现代理接口方法并作为服务提供者的真实类 class RealClass : public iProxy { public: RealClass() {}; ~RealClass() {}; // 实现接口 void methodOne() {}; void methodTwo() {}; private: CommClass CommObject; };
登录后复制
结论
示例代理模式是任何软件工程师的箭筒中的重要箭头。通过使用组合原则,我们可以控制对内部对象的访问,添加额外的逻辑(例如缓存和 API 日志记录)以及增加安全性。它允许延迟初始化,这在资源受限的环境中很有用。确实存在某些缺点,例如增加开销和复杂性,因此,这不是一个万能的解决方案。
虽然代理模式为许多常见的设计挑战提供了强大的解决方案,但任何设计模式都应谨慎使用,以免使您的设计过于复杂。始终从较简单的面向对象原则开始,然后在您的架构开始类似于特定模式时切换到设计模式。
以上就是软件设计模式和原则的详细内容,更多请关注其它相关文章!