首页 > 编程语言 >代码大全继承派生覆盖子程序,但没有任何操作

代码大全继承派生覆盖子程序,但没有任何操作

时间:2024-08-01 09:49:51浏览次数:9  
标签:派生 继承 子类 爪子 Cat Scratch Claw 子程序 大全

派生后覆盖了某个子程序,但在其中没做任何操作,这种情况也值得怀疑这通常表明基类的设计中有错误。

 

举例来说,假设你有一个Cat(猫)类,它有一个Scratch()(抓)成员函数,可是最终你发现有些猫的爪尖儿没了,不能抓了。你可能想从Cat类派生一个叫 scratchiesscat(不能抓的猫)的类,然后覆盖scratch()方法让它什么都不做。但这种做法有这么几个问题。 它修改了 cat 类的接口所表达的语义,因此破坏了Cat 类所代表的抽象(即接口契约) 当你从它进一步派生出其他派生类时,采用这一做法会迅速失控。如果你又发现有只猫没有尾巴该怎么办?或者有只猫不捉老鼠呢?再或者有只猫不喝牛奶?最终你会派生出一堆类似ScratchlessTaillessMicelessMi1klessCat(不能抓、没尾巴、不捉老鼠、不喝牛奶的猫)这样的派生类来。 采用这种做法一段时间后,代码会逐渐变得混乱而难以维护,因为基类的接口和行为几乎无法让人理解其派生类的行为。 修正这一问题的位置不是在派生类,而是在最初的Cat类中。应该创建一个Claw(爪子)类并让Cat类包含它。问题的根源在于做了所有猫都能抓的假设,因此应该从源头上解决问题,而不是到发现问题的地方修补。

   
这段描述提到的问题和解决策略涉及到面向对象设计中的几个重要概念,包括里氏替换原则(LSP)、接口的一致性、以及如何正确地使用继承。以下是对这个问题的分析和建议:

### 问题分析

1. **接口一致性**:
   - 如果 `Cat` 类有一个 `Scratch()` 方法,那么所有 `Cat` 的实例都应该能够执行抓的动作。如果某个 `Cat` 的子类不能抓,这违反了接口的一致性。

2. **继承滥用**:
   - 通过创建一个不能抓的 `Cat` 子类并覆盖 `Scratch()` 方法使其无效,这种做法滥用了继承。继承应该用来表示 "是一个"(is-a)关系,而不是 "像是一个"(acts-like-a)关系。

3. **过度细分**:
   - 如果继续这种设计方式,可能会导致大量的子类,每个子类都缺少一些 `Cat` 类的特性,这会导致代码的复杂性和难以维护。

### 解决策略

1. **重新设计基类**:
   - 考虑在 `Cat` 类中使用组合,而不是继承。例如,创建一个 `Claw` 类,`Cat` 类包含一个或多个 `Claw` 对象。这样,`Cat` 类的行为就依赖于 `Claw` 对象的状态。

2. **使用条件逻辑**:
   - 在 `Cat` 类的 `Scratch()` 方法中,添加逻辑来判断是否可以执行抓的动作,例如检查 `Claw` 对象是否存在。

3. **接口契约**:
   - 确保 `Cat` 类的接口契约清晰明确,所有继承自 `Cat` 的子类都应该遵守这些契约。

4. **使用状态模式**:
   - 如果 `Cat` 的行为会根据其状态改变,可以使用状态模式来管理这些行为,而不是通过创建大量的子类。

5. **避免过度继承**:
   - 避免创建过多的子类来表示不同的行为或状态。应该寻找更通用的设计模式或原则来简化设计。

6. **使用多态**:
   - 如果 `Cat` 类的不同子类需要有不同的行为,可以使用多态性来实现,而不是通过覆盖方法使其无效。

7. **代码重构**:
   - 如果现有的继承结构已经变得复杂,考虑重构代码,将继承结构替换为更合理的设计模式。

8. **文档和沟通**:
   - 在团队中确保设计决策有充分的文档记录和沟通,以便所有开发人员理解设计意图和约束。

通过这些策略,可以避免继承层次结构的滥用,并设计出更灵活、更可维护的系统。重要的是要理解继承应该谨慎使用,并且在设计时考虑到所有潜在的变化和扩展。

  

 

 

在Go语言中,我们可以通过组合而非继承来解决这个问题。下面是一个简单的示例,演示了如何使用组合来实现这个设计:

```go
package main

import (
	"fmt"
)

// Claw 表示猫的爪子,包含是否可以抓的属性
type Claw struct {
	canScratch bool
}

// NewClaw 创建一个新的爪子实例,默认是可以抓的
func NewClaw(canScratch bool) *Claw {
	return &Claw{canScratch: canScratch}
}

// Cat 表示猫,包含猫的名字和一个爪子对象
type Cat struct {
	name string
	claw *Claw
}

// NewCat 创建一个新的猫实例
func NewCat(name string, claw *Claw) *Cat {
	return &Cat{name: name, claw: claw}
}

// Scratch 模拟猫抓的行为,根据爪子的状态决定是否能抓
func (c *Cat) Scratch() {
	if c. claw.canScratch {
		fmt.Printf("%s scratches the post.\n", c.name)
	} else {
		fmt.Printf("%s tries to scratch but cannot.\n", c.name)
	}
}

func main() {
	// 创建一个正常的爪子和猫
	normalClaw := NewClaw(true)
	normalCat := NewCat("Whiskers", normalClaw)
	normalCat.Scratch()

	// 创建一个不能抓的爪子
	scratchlessClaw := NewClaw(false)

	// 创建一个不能抓的猫
	scratchlessCat := NewCat("Paws", scratchlessClaw)
	scratchlessCat.Scratch()
}
```

在这个示例中:

- 我们定义了一个 `Claw` 结构体来表示猫的爪子,其中包含一个 `canScratch` 字段,用以表示爪子是否可以抓。
- `Cat` 结构体通过组合包含一个 `Claw` 对象,而不是通过继承来共享行为。
- `Cat` 类的 `Scratch` 方法根据 `Claw` 对象的 `canScratch` 属性来决定猫是否可以抓。
- 在 `main` 函数中,我们创建了两个 `Cat` 实例,一个具有正常的爪子,另一个具有不能抓的爪子,然后调用它们的 `Scratch` 方法来演示不同行为。

这种设计避免了通过继承创建大量具有不同行为的子类的问题,同时也保持了代码的清晰和可维护性。如果将来需要添加更多的行为或属性,我们可以简单地修改 `Claw` 类或其他相关类,而不需要创建大量的新的 `Cat` 子类。

  

标签:派生,继承,子类,爪子,Cat,Scratch,Claw,子程序,大全
From: https://www.cnblogs.com/gongxianjin/p/18336031

相关文章

  • 代码大全C语言如何使用ADT
    面向对象的编程语言能自动支持对同一ADT的多份实例的处理。如果你只是在面向对象的环境中工作,那你根本就不用自己操心处理多个实例的实现细节了恭喜你(你可以直接去读下一节“ADT和类”。)!如果你是在像C语言这样的非面向对象的环境中工作,你就必须自己手工实现支持处理多个实例的......
  • 代码大全不要让 ADT依赖于其存储介质
    Q:不要让ADT依赖于其存储介质假设你有一张保险费率表,它太大了,因此只能保存到磁盘上。你可能想把它称做一个“费率文件”然后编出类似RateFile.Read()这样的访问器子程序(accessroutine)。然而当你把它称做一个“文件”时,已经暴露了过多的数据信息。一旦对程序进行修改,把这张表......
  • 6万字嵌入式最全八股文面试题大全及参考答案(持续更新)
    目录冒泡排序算法的平均时间复杂度和最坏时间复杂度分别是多少?在什么情况下使用冒泡排序较为合适?选择排序算法是稳定的排序算法吗?为什么?插入排序在近乎有序的数组中表现如何?为什么?快速排序的基本思想是什么?它在最坏情况下的时间复杂度是多少?归并排序的空间复杂度是多少?如......
  • 新网站大全目录网址导航整站源码,支持网址小程序提交,自适应模板
    1、一键获取目标站 SEO 信息,7.5 版本增加会员中心一键获取网站信息网站权重,增加小程序提交发布,全新自适应模板;2、可设置游客提交、游客提交人工审核,会员免审提交,会员提交人工审核,VIP 会员免审核,不同会员组提交分别设置免审或审核;3、自助充值积分,自助充值会员(可随意设置充......
  • Java面试题大全(四)
    91.Java开发设计七大原则在Java编程中,有一些基本的设计原则和模式,被广泛接受为最佳实践。以下是七个主要的Java开发原则:单一职责原则(SRP)一个类应该只有一个引起它变化的原因。开放-封闭原则(OCP)类应该是可扩展的,但是不可修改。李氏替换原则(LSP)子类型必须能够替换掉它们......
  • 10:Pycharm 常用快捷键大全
    本文对Pycharm常用快捷键进行了汇总整理,如果学习,相信这些快捷键一定能提高Python编程的效率。2.代码补全  当你输入代码时,按下Tab键可以自动补全当前的代码或变量名。如果有多个可能的选项,你可以按下Tab键多次来循环浏览这些选项。3.代码缩进  在Python中,代码块的缩进非......
  • 【python学习】retry库用法大全!附示例代码
    Retry是一个用于Python的库,用于在函数调用失败时自动重试。它的目标是简化重试逻辑的编写,处理由于临时性问题(如网络故障、API限制等)导致的失败。Retry的主要特点包括:简单易用:只需使用装饰器或上下文管理器即可实现重试功能。灵活配置:可以配置重试次数、重试间隔、异常......
  • 收藏多年的线程安全问题大全笔记(1),笔记一生一起走,那些日子不再有
    本篇会加入个人的所谓鱼式疯言❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言而是理解过并总结出来通俗易懂的大白话,小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.......
  • 代码大全中保持松散耦合的demo
    Q:假设你有一段子程序,通过输入雇用日期和工作级别来查询员工每年获得的休假数量。这段子程序被命名为LookupVacationBenefit()。假设在另一个模块里已经有了一个employee对象,其中包含了雇用日期和工作级别,以及其他一些信息,该模块把这种对象传给LookupVacationBenefit()。按照其他......
  • 病毒大全
    分享一下我的病毒以下所有病毒禁止非(bu)法(shi)使用,否则后果自负!!!1.bat病毒最危险的病毒(保存为666.bat)后果:开机就关机解决办法:重装系统点击查看代码Copy666.bat“%userprofile%\AppData\Roaming\Microsoft\Windows\StartMenu\Programs\Startup\”taskkill/f/f......