【设计模式】设计原则--面向接口编程你理解的对吗?

最近看了《Head First Design Patterns》这本书。正如其名,这本书讲的是设计模式(Design Patterns),而这本书的第一章,讲的是很重要的一些设计原则(Design Principles)。

  • Identify the aspects of your application that vary and separate them from what stays the same.(识别应用程序中各个方面的变化,并将它们与保持不变的部分分开。)
  • Program to an interface, not an implementation.(面向接口而不是实现编程。)
  • Favor composition over inheritance.(优先考虑组成而不是继承。)

其中令我感触颇深的是,“面向接口而不是实现编程”颠覆了我一直以来的认识。

文章中示例代码为原书中截图,C#代码参照文末提供链接。

开始

书中用了一个很形象的示例:模拟鸭子程序(SimUDuck)。系统的最初设计使用标准的OO技术,并创建了一个Duck基类,所有其他Duck类型都继承自该基类。

设计系统时考虑到鸭子都会发出叫声,而且都会游泳,于是将Quack方法和Swim方法定义到Duck基类中并实现;此外,并不是所有的鸭子都是长得一样的,那么将Display方法在Duck基类中定义为抽象的,所有继承自Duck基类的子类编写自己的实现。

新的需求产生了!我们需要让系统中的鸭子可以飞。从面向对象的角度来考虑,如果我们想要代码重用,只需要在Duck基类中添加方法Fly并实现它——所有的鸭子子类都是继承自Duck基类的——就实现了让鸭子飞的功能。我们通过继承实现了代码重用,很轻松就解决了问题。

也许我们需要深入考虑一下,所有的鸭子都会飞吗?玩具橡胶鸭呢?我们把Fly方法的定义及实现放到了Duck基类中,所有继承自它的子类都继承到了Fly方法,其中也包括了不应继承Fly方法的子类。如果按照上面的方案,那我们只能在RubberDuck橡胶鸭子类中重写父类的Fly方法让RubberDuck执行Fly的时候什么都不做。

再深入一些,如果我们的系统中除了橡胶鸭外,还有其他各种鸭子,比如木头鸭子呢?这时DecoyDuck木头鸭子继承来的Quack方法出现了问题——木头鸭子不会叫!我们只好再把DecoyDuck中的Quack方法重写了......

如果我们改用接口会怎么样呢?把QuackFly方法从基类中拿出来,分别在IQuackableIFlyable接口中定义,然后我们不同的子类根据需要来继承接口,并实现QuackFly方法。

当我们有很多个子类鸭子的时候,就要分别为每个继承了IQuackableIFlyable接口的子类来编写QuackFly的实现方法,这完全破坏了代码重用!值得注意的是,虽然我们在这里使用了接口,但这并不是面向接口编程。

封装变化

这里引入第一条设计原则:Identify the aspects of your application that vary and separate them from what stays the same.(识别应用程序中各个方面的变化,并将它们与保持不变的部分分开。)

换言之:take the parts that vary and encapsulate them, so that later you can alter or extend the parts that vary without affecting those that don’t.(将变化的部分封装起来,以便以后可以更改或扩展变化的部分而不会影响那些不变的部分。)

这样带来的好处是,我们可以进行更少的代码更改来实现需求功能,减少因代码更改而带来的意想不到的影响,并且提高了系统灵活性。

我们知道Duck的不同子类中,QuackFly的行为是会发生变化的,那么我们将QuackFly方法从Duck基类中拿出来,并为QuackFly方法分别创建一些类,来实现各种不同的行为。

面向接口而不是实现编程

设计原则:Program to an interface, not an implementation.(面向接口而不是实现编程。)

在这里,面向接口而不是实现编程,和封装变化是相辅相成的。值得注意的是,这里所说的接口,并不是我们代码层面上的interface,"面向接口编程(Program to an interface)所表达的意思实际上是面向基类编程(Program to a supertype),核心思想是利用面向对象编程的多态性。在代码的具体实现上,我们既可以用Interface来作为我们所面向的接口,也可以用一个抽象的基类来作为我们面向的接口。遵循面向接口编程,对模拟鸭子程序的FlyQuack行为进行设计,我们可以定义接口IFlyBehaviorIQuackBehavior来代表行为FlyQuack,接口的实现则是行为具体的表现形式。我们可以将接口的不同实现类,来赋值给Duck的不同子类,从而利用继承多态来实现面向接口编程。类图如下:

FlyBehavior是一个所有不同的Fly类都要继承的接口或基类,其中定义了Fly方法。不同的Fly类有不同的Fly方法实现。QuackBehavior类似。

接下来我们对Duck类进行更改,将FlyQuack委托出去,不再通过Duck类或其子类的方法来实现。

  1. 首先我们在Duck类中定义两个代表FlyBehaviorQuackBehavior的变量。这两个变量的值是不同的Duck所需要的特定FlyBehaviorQuackBehavior的子类:
  2. 然后实现PerformQuack方法:
  3. FlyBehaviorQuackBehavior赋值:

至此我们就实现了面向接口编程。

我们还可以动态设置Duck的行为,只需要为Duck类的FlyBehaviorQuackBehavior提供Set方法(在C#中,使用自动属性即可)。

优先考虑组成而不是继承

Favor composition over inheritance.(优先考虑组成而不是继承。)

HAS-A(有一个)比IS-A(是一个)要好。HAS-A在我们的Duck系统中可以描述为:每一个DuckHAS-A有一个FlyBehavior,还HAS-A有一个QuackBehaviorDuck委托它们来处理FlyQuack的行为。优先考虑组合而不是继承让我们的系统拥有更多的灵活性,封装变化,还可以在运行时动态更改类的行为。

示例代码

示例代码

原文地址:https://www.cnblogs.com/realZhangChi/p/12186474.html

时间: 2024-12-07 23:40:34

【设计模式】设计原则--面向接口编程你理解的对吗?的相关文章

Python设计模式——设计原则

1.单一职责原则:每个类都只有一个职责,修改一个类的理由只有一个 2.开放-封闭远程(OCP):开放是指可拓展性好,封闭是指一旦一个类写好了,就尽量不要修改里面的代码,通过拓展(继承,重写等)来使旧的类满足新的需求,而不是修改一个类里面的代码. 3.依赖倒转原则:高层模块不应该依赖底层模块,两个都应该依赖抽象:抽象不应该依赖细节,细节应该依赖抽象.底层模块例如很多工具类,例如专门用于管理sql连接的类,管理文件,管理socket连接的类,高层类指具体实现需求的类.高层类和底层类都不应该相互依赖,

设计模式设计原则

设计原则详解 设计模式存在的根本原因是为了代码复用,增加可维护性. 开闭原则:对扩展开放,对修改关闭 里氏转换原则:子类继承父类,单独掉完全可以运行 依赖倒转原则:引用一个对象,如果这个对象有底层类型,直接引用底层. 接口隔离原则:每一个接口应该是一种角色 合成/聚合复用原则:新的对象应使用一些已有的对象,使之成为新对象的一部分 迪米特原则:一个对象应对其他对象有尽可能少的了解 综述:站在巨人的肩膀上整体HOLD系统架构 设计模式概念解读 1.设计模式概念文字解读 设计模式是一套被繁复使用,思想

设计模式.设计原则-单一职责原则

1:什么情况下 会使用到单一职责原则设计模式? 当同一个类中同时出现业务和属性等代码的时候或者当同一个类中要做多样事情的时候,就需要将其抽象出来,做成多种不同的接口,以便后续方便扩展单一职责:原则要求一个接口或者类只有一个原因引起变化,也就是一个接口或者类只有一个职责,它就负责一件事情 单一原则的好处:类的复杂性降低,实现责任清晰明确可读性高,复杂性降低可维护性提高,可读性提高变更引起风险性降低,变更是必不可少的,如果接口修改,只影响对应的实现类,对其他接口没有影响 如上图所示:Perion类这

软件设计原则和方法通俗理解

网上有很多关于软件设计原则的说法,很精确,很官方,但是对于有些初学者来说可能是不知所云,到最后把自己给郁闷到了,学习软件应该是一件愉快的事情. 那么软件设计原则有哪些呢? (1)可靠性 做出一个可靠的软件,跟女人找一个可靠的男人一样,女人找男人,需要男人品质好,人品好,靠谱,可信赖,可依靠,身材高大,等等.软件设计也是一样,在软件的设计阶段就要非常注意软件的可靠性,不要等到最后用的时候发现软件这里不行那里不行,或者说在使用软件过程中一旦发现问题还是可以恢复使用,不能直接崩溃. (2)健壮性 这个

设计模式-设计原则

1. 单一职责原则(Single Responsibility Principle,SRP):就一个类而言,应该仅有一个引起它变化的原因. 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力.这种耦合会导致脆弱的设计,当变化发生时,设计会遭到意想不到的破坏. 判断是否应该分离出类来,就是如果你能够想到多余一个的动机去改变一个类,那么这个类就具有多余一个的职责. 2. 开放-封闭原则(Open-Closed Principle,OCP):

设计模式.设计原则-依赖倒置原则

1:依赖倒置原则在Java语言中的表现就是: 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的.接口或抽象类不依赖于实现类.实现类依赖与接口或抽象类. 采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并发开发引起的风险,提高代码的可读性和可维护性.依赖是可以传递的.只要做到抽象依赖,即使是多层的依赖传递也无所畏惧. 对象的依赖关系又三种方式来传递:1:构造函数传递依赖对象2:Setter方法传递依赖对象 3:接口声明依赖对象 2:最佳实践:

菜菜读设计模式设计模式——设计原则:面向对象

1.面向对象语言(OOP) 面向对象语言最基本的概念就是类与对象,只有拥有这两个概念的语言才是面向对象语言 一般来说面向对象语言拥有四个特征:封装.继承.抽象.多态 但并不是必须具备这四种特性的语言才能成为面向对象语言,比如说 Go 语言,它没有继承的特性,但我们仍认为它是面向对象语言 2.封装.抽象.继承.多态 封装:类通过暴露有限的访问接口,授权外部仅能以类提供的函数来访问内部信息或数据. 实现封装的机制:访问权限控制 (public\protect\default\private)   同

Pattern-No.00 设计模式设计原则

1)找出应用中可能需要变化的地方,把他们独立出来,不要和那些不需要变化的代码混合在一块 2)针对接口编程,而不是针对实现编程.针对接口编程,实际上指针对超类编程.超类型可以是一个接口类,也可以是一个抽象类.具体实现具体对待使用 3)多用组合,少用继承."有一个"比"是一个"更好

了解设计模式先从六大设计原则说起

了解设计模式的朋友们,想必都听说过"六大设计原则"吧.其实最经典的 23 种设计模式中或多或少地都在使用这些设计原则,也就是说,设计模式是站在设计原则的基础之上的.所以在学习设计模式之前,很有必要对这些设计原则先做一下了解. GoF(四人帮),传说中的四位大神们,他们联手搞出了一套设计模式,堪称 OOD(面向对象设计)的经典之作!震惊了整个软件开发领域.但这四个老家伙非常怪异,总是喜欢显摆一些高深的理论,甚至有时候不说人话,十分让人费解. 除了最经典的六大设计原则以外,还有一些其他的设