鸭子模型

因此,您知道一般的编码方式,了解面向对象的编程,学习过C ++并完成了至少一门软件开发课程(如果您还没有,那么这些文章不适合您)。 如果您至少知道一种编程语言,则可以轻松编写软件,但是您的代码有好处吗? 能做得更好吗? 它干净吗(这到底意味着什么)? 您的架构好吗?您应该使用其他架构吗? 那设计模式呢? 这些是我刚开始时遇到的一些问题,回答这些问题有助于我提高专业水平。 这就是为什么我将这些系列SOLID编写为Rock设计原理的原因。 大号 iskov公司的S ubstitution P rinciple在C ++中是第二次在这个系列,我将在这里讨论的原则。

您在本系列文章中看到的代码段是简化而不是复杂的。 因此,您经常看到我不使用诸如override,final,public(同时继承)之类的关键字只是为了使代码紧凑且可消耗(大部分时间)是在单个标准屏幕尺寸内。 我也更喜欢使用struct而不是class来保存行,因为有时不写“ public:”,并且还错过了虚拟析构函数 ,构造函数, 复制构造函数 ,前缀std ::,故意删除了动态内存。 我也认为自己是一个务实的人,他希望以最简单的方式而不是标准的方式或使用术语来传达想法。

注意:

  • 如果您直接在这里偶然发现,那么我建议您经历一下什么是设计模式? 首先,即使是微不足道的。 我相信它将鼓励您探索有关此主题的更多信息。
  • 在本系列文章中遇到的所有这些代码都是使用C ++ 20编译的(尽管在大多数情况下,我使用的是Modern C ++的功能,直到C ++ 17为止)。 因此,如果您无权访问最新的编译器,则可以使用https://wandbox.org/ ,它也已预装了boost库。

意图

子类型必须可以替代其基本类型,而不会改变程序的正确性

  • 如果我在C ++上下文中解决这个问题,那么字面意思是使用基类的指针/引用的函数必须能够被其派生类替代。
  • Liskov替代原则围绕确保正确使用继承。

违反李斯科夫的替代原则

  • 一个说明LSP的伟大而传统的例子是,有时以自然语言听起来正确的东西有时在代码中不太起作用。
  • 在数学中,正方形是矩形。 实际上,它是矩形的一种特殊形式。 “ IS A”使您想使用继承对其进行建模。 但是,如果在代码中让Square从Rectangle派生,则Square应该可以在您期望Rectangle的任何地方使用。 这导致一些奇怪的行为,如下所示:
struct Rectangle {Rectangle( const uint32_t width, const uint32_t height) : m_width{width}, m_height{height} {}uint32_t get_width() const { return m_width; }uint32_t get_height() const { return m_height; }virtual void set_width ( const uint32_t width)  { this ->m_width = width; }virtual void set_height ( const uint32_t height)  { this ->m_height = height; }uint32_t area() const { return m_width * m_height; }protected :uint32_t m_width, m_height;
};struct Square : Rectangle {Square( uint32_t size) : Rectangle(size, size) {}void set_width ( const uint32_t width) override  { this ->m_width = m_height = width; }void set_height ( const uint32_t height) override  { this ->m_height = m_width = height; }
};void process (Rectangle &r)  {uint32_t w = r.get_width();r.set_height( 10 );assert((w * 10 ) == r.area()); // Fails for Square <--------------------
}int main ()  {Rectangle r{ 5 , 5 };process(r);Square s{ 5 };process(s);return EXIT_SUCCESS;
}

  • 如上所示,我们在void process(Rectangle&r)函数中违反了Liskovs的替代原理。 因此Square不是Rectangle的有效替代品。
  • 如果从设计角度来看,从Rectangle继承Square的想法不是一个好主意。 因为Square没有高度和宽度,所以它具有边的大小/长度。

C ++中Liskov替代原理的示例

不太好

void process (Rectangle &r)  {uint32_t w = r.get_width();r.set_height( 10 );if ( dynamic_cast <Square *>(&r) != nullptr )assert((r.get_width() * r.get_width()) == r.area());elseassert((w * 10 ) == r.area());
}

  • 经常表示违反LSP的常见代码气味是多态代码块中存在类型检查代码。
  • 例如,如果您在Foo类型的对象集合上有一个std :: for_each循环,并且在此循环内检查是否Foo实际上是Bar(Foo的子类型),那么几乎可以肯定违反LSP。 相反,您应该确保Bar在所有方面都可以代替Foo,而不必包括此类支票。

一种好的方法

void process (Rectangle &r)  {uint32_t w = r.get_width();r.set_height( 10 );if (r.is_square())assert((r.get_width() * r.get_width()) == r.area());elseassert((w * 10 ) == r.area());
}

  • 无需为Square创建单独的类。 相反,您可以简单地在Rectangle类中检查是否有bool标志来验证Square属性。 虽然不是推荐的方式。

使用适当的继承层次结构

struct Shape {virtual uint32_t area () const  = 0 ;
};struct Rectangle : Shape {Rectangle( const uint32_t width, const uint32_t height) : m_width{width}, m_height{height} {}uint32_t get_width() const { return m_width; }uint32_t get_height() const { return m_height; }virtual void set_width ( const uint32_t width)  { this ->m_width = width; }virtual void set_height ( const uint32_t height)  { this ->m_height = height; }uint32_t area() const override { return m_width * m_height; }private :uint32_t m_width, m_height;
};struct Square : Shape {Square( uint32_t size) : m_size(size) {}void set_size ( const uint32_t size)  { this ->m_size = size; }uint32_t area() const override { return m_size * m_size; }private :uint32_t m_size;
};void process (Shape &s)  {// Use polymorphic behaviour only i.e. area()
}

具有工厂模式

  • 仍然需要创建或更改来处理Shape,然后应尝试使用Virtual Constructor和Virtual Copy Constructor,即Factory Pattern 。
struct ShapeFactory {static Shape CreateRectangle ( uint32_t width, uint32_t height) ;static Shape CreateSquare ( uint32_t size) ;
};

里斯科夫替代原则的好处

=>相容性

  • 它实现了多个发行版和补丁之间的二进制兼容性。 换句话说,它使客户端代码不受影响。

=>类型安全

  • 这是通过继承处理类型安全的最简单方法,因为在继承时不允许类型发生变化

=>可维护性

  • 遵守LSP的代码之间相互依赖,并鼓励代码可重用。
  • 遵循LSP的代码是进行正确抽象的代码。

用C ++制作Liskov替代原理友好软件的标尺

  • 在大多数面向对象编程的介绍中,继承都以与继承对象的“ IS-A”关系进行讨论。 但是,这是必要的,但还不够。 如果将一个对象与继承的对象始终保持“ IS-SUBSTITUTABLE-FOR”的关系,则可以更恰当地说。
  • 使用抽象基类的全部目的是,以便将来可以编写一个新的子类并将其插入现有的,有效的,经过测试的代码中。 一个崇高的目标,但如何实现呢? 首先,首先分解问题空间-域。 其次,用简明的英语表达您的合同/界面/ 虚拟方法 。

结束语

不要误会我的意思,我喜欢SOLID及其提倡的方法。 但这是
只是深层原则的基础。 上面的例子清楚地说明了这个原则在努力进行哪些工作,即松散的耦合和确保正确的继承

现在,到那里去,使您的子类可以互换,并感谢Barbara Liskov博士的有用原则。

/!\:最初发布于 www.vishalchovatiya.com

如果您还没有阅读我以前有关设计原则的文章,那么下面是快速链接:

  1. SRP-单一责任原则  
  2. OCP-开放/封闭原则  
  3. LSP-Liskov替代原理  
  4. ISP-接口隔离原理  
  5. DIP-依赖倒置原则

翻译自: https://hackernoon.com/if-it-looks-like-a-duck-quacks-like-a-duck-but-needs-batteries-you-have-the-wrong-abstraction-1akm32ln

鸭子模型

鸭子模型_如果它看起来像鸭子,嘎嘎像鸭子,但需要电池-您的抽象错误相关推荐

  1. 天天学Python(一)—鸭子模型

    前言:很早之前看过Python,鉴于遗忘太快,以此记之 鸭子模型: 一个对象只要"看起来像鸭子,走起路来像鸭子",那它就可以被看做是鸭子 这是动态语言奇妙的地方 看下面的代码: # ...

  2. lr模型和dnn模型_建立ML或DNN模型的技巧

    lr模型和dnn模型 机器学习 (Machine Learning) Everyone can fit data into any model machine learning or deep lea ...

  3. 透过性别看世界_透过树林看森林

    透过性别看世界 决策树如何运作 (How a Decision Tree Works) Pictorially, a decision tree is like a flow-chart where ...

  4. ai模型_这就是AI的样子:用于回答问题的BiDAF模型

    ai模型 We at Zetane are all about democratizing AI, but getting to the laudable goal of empowering mor ...

  5. Linux设备模型_导航篇

    Linux设备模型_导航篇 1. Linux设备模型系列文章说明 2. Linux设备模型系列文章目录 2.0 [Linux内核的整体架构](https://zhuanlan.zhihu.com/p/ ...

  6. [转]编程语言中的 鸭子模型(duck typing)

    在学习Python的时候发现了鸭子类型这个术语,听起来好像很有意思一样,所以把它记下来. 鸭子类型的核心概念在于一个对象的有效语义,不是继承自特定的类或者实现特定的方法,而是 由当前的属性和方法集合决 ...

  7. 生成模型和判别模型_生成模型和判别模型简介

    生成模型和判别模型 Intro 介绍 Recently I gave a presentation at work, where I explained how I solved some probl ...

  8. ansys电力变压器模型_变压器模型……一切是如何开始的?

    ansys电力变压器模型 Transformer models have revolutionised the field of Natural Language Processing but, ho ...

  9. 多元时间序列回归模型_多元时间序列分析和预测:将向量自回归(VAR)模型应用于实际的多元数据集...

    多元时间序列回归模型 Multivariate Time Series Analysis 多元时间序列分析 A univariate time series data contains only on ...

最新文章

  1. Windows Azure 解决方案系列:组合拍卖供应商以云服务快速拓展,并节省成本
  2. ASP.NET文件上传和下载
  3. 二分图最大权匹配 KM算法
  4. 【C++】静态成员 static
  5. 在eclipse中指定启动时java的位置
  6. 天猫服务系统的架构和经验
  7. 一行代码引来的安全漏洞,就让我们丢失了整个服务器的控制权
  8. 手把手教你进行pip换源,让你的Python库下载嗖嗖的
  9. [译] Object.assign 和 Object Spread 之争, 用谁?
  10. mysql常用调试工具_最常用的8款PHP调试工具
  11. 无废话WPF系列16:资源
  12. web前端设计与开发大作业(五)----期末设计报告
  13. 微信小程序点击按钮弹出弹窗_微信小程序弹窗,微信小程序页面跳转、弹出框...
  14. 【JS逆向系列】某服务器平台sm系列算法分析
  15. 根据关系图非常简单的求出三种关系闭包(自反闭包、对称闭包、传递闭包)附练习题
  16. 同济大学计算机考试模拟大一上,同济大学大学计算机access作业答案.docx
  17. 微信小程序:修改单选radio大小样式
  18. 计算时间复杂度--(简单版)
  19. 利用云服务器搭建hadoop集群
  20. 【微信小程序入门到精通】— 配置合法域名、进行网络数据请求(GET、POST)

热门文章

  1. 启动子容器失败:A child container failed during start
  2. 程序员必备:拯救颈椎,只需三个步骤
  3. JavaScript中的参数传递
  4. 0017 正方体的表面积和体积
  5. 华为CaaS开放平台产品宣传片
  6. ZZNUOJ_C语言1046:奇数的乘积(完整代码)
  7. 流氓软件卸载之——WPS猎豹热点
  8. ROS通信机制--键盘控制乌龟运动线速度角速度XYZ值的解释
  9. 移动运营商AIS泄漏了83亿条用户数据 容量约4.7 TB
  10. 客户文章|南方医科大学李克玄团队破解肠道宏病毒与心肌病关系