设计模式学习(一):多用组合少用继承(C#)
时间:2022-04-29
本文章向大家介绍设计模式学习(一):多用组合少用继承(C#),主要内容包括《深入浅出设计模式》学习笔记第一章、原始需求和设计、第一次需求变更、问题发生了,因为不是所有的鸭子都会飞、也许,可以用接口?、现在的情况是:、找出应用中可能需要变化的地方,把它们独立起来,不要和那些不需要发生变化的代码混在一起。、针对接口编程而不是针对实现编程。、整合鸭子的行为、测试鸭子、需求又变了,要求鸭子的行为可以随时改变、设计原则:多用组合,少用继承、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
《深入浅出设计模式》学习笔记第一章
原始需求和设计
事情是这样开始的,公司需要做一套程序,鸭子,设计如下:
一个鸭子父类,多个派生类,三个可override的方法。
第一次需求变更
我们要会飞的鸭子!!!!!
所以我们做了如下的更改:
父类加了fly方法,嗯,所有的鸭子都会飞了,需求实现!
问题发生了,因为不是所有的鸭子都会飞
我们可以在派生类中把父类的fly方法中的内容覆盖掉,那么这个鸭子就不会飞了!
那么问题又来了,如果再出现几个新型鸭子都不会飞,是不是每个都得覆盖一遍fly方法啊????
也许,可以用接口?
把每个方法都做成接口,如图:
这是超笨的方法,如果一些鸭子的飞行方式发生变化,那么得改多少个类啊。。。
现在的情况是:
继承不行,因为鸭子的行为(需求)在子类里面不断变化,而使用接口又无法进行复用。
幸好,面向对象软件开发有这样一个原则:
找出应用中可能需要变化的地方,把它们独立起来,不要和那些不需要发生变化的代码混在一起。
这句话另一种思考方式就是:把变化的部分取出并封装起来,以便以后可以轻松的改动或扩展,而不影响其他部分。
所以我们应该把鸭子的行为都提取出来。
根据需求,我们知道鸭子的fly和quack行为经常发生变化,所以我们现在的设计是这样的:
设计原则:
针对接口编程而不是针对实现编程。
这是变化的部分,对于Fly和Quack分别定义接口。
namespace DesignPatterns.Intro.Bases
{
public interface IFlyBehavior
{
void Fly();
}
}
namespace DesignPatterns.Intro.Bases
{
public interface IQuackBehavior
{
void Quack();
}
}
然后实现几种类型的Fly和Quack:
namespace DesignPatterns.Intro.Derives
{
public class Squeak: IQuackBehavior
{
public void Quack()
{
Console.WriteLine("吱吱");
}
}
}
namespace DesignPatterns.Intro.Derives
{
public class NormalQuack: IQuackBehavior
{
public void Quack()
{
Console.WriteLine("呱呱");
}
}
}
namespace DesignPatterns.Intro.Derives
{
public class MuteQuack: IQuackBehavior
{
public void Quack()
{
Console.WriteLine("---------");
}
}
}
整合鸭子的行为
让我们来定义鸭子:
namespace ConsoleApp2.Bases
{
public abstract class Duck
{
private readonly IFlyBehavior _flyBehavior;
private readonly IQuackBehavior _quackBehavior;
protected Duck(IFlyBehavior flyBehavior = null, IQuackBehavior quackBehavior = null)
{
_flyBehavior = flyBehavior ?? new FlyNoWay();
_quackBehavior = quackBehavior ?? new MuteQuack();
}
public abstract void Display();
public void PerformFly()
{
_flyBehavior.Fly();
}
public void PerformQuack()
{
_quackBehavior.Quack();
}
public void Swim()
{
Console.WriteLine("所有的鸭子都会游泳");
}
}
}
这是鸭子的抽象类。
建立实际的鸭子:
namespace ConsoleApp2.Derives
{
public class MallardDuck: Duck
{
public MallardDuck(IFlyBehavior flyBehavior = null, IQuackBehavior quackBehavior = null) : base(flyBehavior, quackBehavior)
{
}
public override void Display()
{
Console.WriteLine("我是个野鸭...");
}
}
}
测试鸭子
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
var duck = new MallardDuck(new FlyNoWay(), new NormalQuack());
duck.PerformFly();
duck.PerformQuack();
duck.Display();
Console.ReadLine();
}
}
}
这时,需求终于完成了!
我们的鸭子根据传入的Fly和Quack实现类不同而具有不同的效果!
需求又变了,要求鸭子的行为可以随时改变
这时,我们需要动态设定行为,我们只需要加入Set方法即可:
Duck最新的代码是:
namespace ConsoleApp2.Bases
{
public abstract class Duck
{
public IFlyBehavior FlyBehavior { private get; set; }
public IQuackBehavior QuackBehavior { private get; set; }
protected Duck(IFlyBehavior flyBehavior = null, IQuackBehavior quackBehavior = null)
{
FlyBehavior = flyBehavior ?? new FlyNoWay();
QuackBehavior = quackBehavior ?? new MuteQuack();
}
public abstract void Display();
public void PerformFly()
{
FlyBehavior.Fly();
}
public void PerformQuack()
{
QuackBehavior.Quack();
}
public void Swim()
{
Console.WriteLine("所有的鸭子都会游泳");
}
}
}
测试效果:
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
var duck = new MallardDuck();
duck.PerformFly();
duck.PerformQuack();
duck.Display();
duck.FlyBehavior = new FlyWithWings();
duck.QuackBehavior = new Squeak();
duck.PerformFly();
duck.PerformQuack();
Console.ReadLine();
}
}
}
需求完成!!!
最终结构如下:
设计原则:多用组合,少用继承
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Windows启动HDFS报错 - 系统找不到文件 hadoop。
- Windows启动HDFS报错 - org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z
- Windows启动HDFS报错 - Could not locate Hadoop executable: E:soft_workhadoop-2.6.0binwinutils.exe
- Windows中jps命令无法查看java进程问题
- Windows搭建HDFS 2.6.0(附加搭建Hadoop)
- Windows搭建HBase 2.0.2
- 病毒与安全防护-网络安全
- 应用层安全协议-Kerberos
- 组网设备
- 网络管理
- 3.字体样式-CSS基础
- 求回文数
- 罗马数字转整数
- (十二) 整合spring cloud云架构 - SSO单点登录之OAuth2.0 登出流程(3)
- 树莓派定时任务不生效