HeadFirst 设计模式(1)
HeadFirst设计模式之目录
HeadFirst设计模式之⽬录只有沉淀、积累,才能远航;沉沉浮浮,脚踏实地。
这本书已经闲置了好久,⼼⾎来潮,决定写个⽬录,让⾃⼰坚持看完这本书创建型模式1. (Abstract factory pattern): 提供⼀个接⼝, ⽤于创建相关或依赖对象的家族, ⽽不需要指定具体类.2. (Builder pattern): 使⽤⽣成器模式封装⼀个产品的构造过程, 并允许按步骤构造. 将⼀个复杂对象的构建与它的表⽰分离, 使得同样的构建过程可以创建不同的表⽰.3. (factory method pattern): 定义了⼀个创建对象的接⼝, 但由⼦类决定要实例化的类是哪⼀个. ⼯⼚⽅法让类把实例化推迟到⼦类.4. (prototype pattern): 当创建给定类的实例过程很昂贵或很复杂时, 就使⽤原形模式.5. (Singleton pattern): 确保⼀个类只有⼀个实例, 并提供全局访问点.6. 多例模式(Multition pattern): 在⼀个解决⽅案中结合两个或多个模式, 以解决⼀般或重复发⽣的问题.结构型模式1. : 将⼀个类的接⼝, 转换成客户期望的另⼀个接⼝. 适配器让原本接⼝不兼容的类可以合作⽆间. 对象适配器使⽤组合, 类适配器使⽤多重继承.2. : 使⽤桥接模式通过将实现和抽象放在两个不同的类层次中⽽使它们可以独⽴改变.3. : 允许你将对象组合成树形结构来表现"整体/部分"层次结构. 组合能让客户以⼀致的⽅式处理个别对象以及对象组合.4. : 动态地将责任附加到对象上, 若要扩展功能, 装饰者提供了⽐继承更有弹性的替代⽅案.5. : 提供了⼀个统⼀的接⼝, ⽤来访问⼦系统中的⼀群接⼝. 外观定义了⼀个⾼层接⼝, 让⼦系统更容易使⽤.6. : 如想让某个类的⼀个实例能⽤来提供许多"虚拟实例", 就使⽤蝇量模式.7. : 为另⼀个对象提供⼀个替⾝或占位符以控制对这个对象的访问.⾏为型模式1. : 通过责任链模式, 你可以为某个请求创建⼀个对象链. 每个对象依序检查此请求并对其进⾏处理或者将它传给链中的下⼀个对象.2. : 将"请求"封闭成对象, 以便使⽤不同的请求,队列或者⽇志来参数化其他对象. 命令模式也⽀持可撤销的操作.3. : 使⽤解释器模式为语⾔创建解释器.4. : 提供⼀种⽅法顺序访问⼀个聚合对象中的各个元素, ⽽⼜不暴露其内部的表⽰.5. : 使⽤中介者模式来集中相关对象之间复杂的沟通和控制⽅式.6. : 当你需要让对象返回之前的状态时(例如, 你的⽤户请求"撤销"), 你使⽤备忘录模式.7. : 在对象之间定义⼀对多的依赖, 这样⼀来, 当⼀个对象改变状态, 依赖它的对象都会收到通知, 并⾃动更新.8. : 允许对象在内部状态改变时改变它的⾏为, 对象看起来好象改了它的类.9. : 定义了算法族, 分别封闭起来, 让它们之间可以互相替换, 此模式让算法的变化独⽴于使⽤算法的客户.10. : 在⼀个⽅法中定义⼀个算法的⾻架, ⽽将⼀些步骤延迟到⼦类中. 模板⽅法使得⼦类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤.11. : 当你想要为⼀个对象的组合增加新的能⼒, 且封装并不重要时, 就使⽤访问者模式.七⼤设计原则1. 单⼀职责原则【SINGLE RESPONSIBILITY PRINCIPLE】:⼀个类负责⼀项职责。
一句话的事儿,Headfirst设计模式
⼀句话的事⼉,Headfirst设计模式head first 设计模式,是⽐较有趣的⼀本设计模式的书。
在学校⾥看书和在⼯作时看书,意义是不⼀样的。
在学校时是为读书⽽读书,我们可以从0到1,我们有的是时间。
但是⼯作后就不⼀样。
我觉得这时的书更像是打通⾃⼰任督⼆脉的武功秘诀。
在平时⼯作中,杂七杂⼋地学了⼀些东西,但是却不能融会贯通。
所以还需要通过书来厘清你的思路。
这是写本⽂的出发点,也是我的碎碎念!看完该书后,转换成⾃⼰的语⾔,再表达出来,可能有错(那是⼀定的),但是,有总⽐没有好。
如果有同学能够从中得到些启发,也算是⾃⼰的⼀种幸运吧!我竟试图以⼀句话来描述⼀个设计模式!1. 策略模式!将统⼀的东西作为基类,可变的东西⾏为独⽴出来,在基类中通过变量进⾏引⽤,通过委托变量的⽅式,使⽤setter⽅法将委托变量改变,使其具有⾏为可变性。
⾯向接⼝编程,⽽⾮⾯向类编程。
其好处是,⽤同样的接⼝,通过不同⾏为类的传⼊产⽣不同的效果,便以改变⾏为变得容易。
2. 观察者模式!类似于发布-订阅模式。
存在注册服务,通知的过程。
其实现⽅式可以理解为,注册服务时,将观察者加⼊到队列当中,当主题发⽣变更时,由主题主动依次从观察者队列中依次调⽤,从⽽达到通知主动推送的作⽤。
其好处是,观察者随时注册观察可以实时收到消息,⽽被观察者对此⼀⽆所知,从⽽在达到通知的同时也解藕了。
3. 装饰者模式!以某对象为主要对象,⽣成后,将其传⼊装饰者构造函数中,经过装饰后,再⾏输出的模式。
该模式,可以许多散乱的⽅法独⽴组装出来,⽽不会影响其他变化,该模式是通过继承来实现的。
典型的装饰者模式运⽤,java io 类的继承,有多个主类,及多个装饰类,从⽽⽅便⽤户操作想要的⽅法。
其好处是,在⼤⽅向不变的情况下,可以反复更改主要的⾏为结果,对于⼀些附加类的变化,可以很⽅便地通过该模式进⾏数据再加⼯。
4. ⼯⼚模式!分为简单⼯⼚模式-⼯⼚模式-抽象⼯⼚模式。
HeadFirst 设计模式(1)综述
设计原则4:开-闭原则
• Strategy模式对“开-闭”原则的支持
设计原则4:开-闭原则
• 玉帝遵照“开-闭”原则维护天庭秩序
– 当年孙悟空大闹天空,向天庭发出挑战:“皇帝轮流 做,明年到我家......只教他搬出去,将天宫让与我!” – 太白金星给玉皇大帝 建议道:“降一道招安 圣旨,把他宣来上界... 与他籍名在箓... 一则不动众劳师, 二则收仙有道也。”
• 使用“组合”思路考虑问题
– “汽车”拥有某种或某些“用途” – “汽车”和“用途”独立变化,互不影响
可维护+可扩展+可复用
松耦合 高内聚. OOP: 封装,继承,多态
设 计 模 式
封 闭 开 放 封 装 变 化 面 向 接 口 组 合 复 用 依 赖 倒 置 里 氏 法 则 迪 米 特
逻辑 。。。 物理 一致
能否用封装原理表述?
设计原则1:封装可变性
识别程序中可变的特征, 并将它们与不变的特征分离开来
逻辑相关,物理封装
设计原则1:封装可变性
识别程序中可变的特征, 并将它们与不变的特征分离开来
现实中的封装可变性
维护, 扩展, 复用?
策略模式的优点
• (1)策略模式提供了管理相关的算法族的办 法。
• 继承复用 • 优点 可以很容易的修改或扩展父类的实现
设计原则3:组合优先
• 继承复用的缺点
– 继承破坏封装,因为父类的实现细节完全暴露给子类 (白盒复用) – 父类的实现发生改变,则子类必受牵连 – 继承是静态的,不能在运行时发生改变,不灵活
设计原则3:组合优先
• 组合复用的优点
– 不破坏封装,这种复用是黑盒复用,因为成员对象的内部细 节对新对象保密 – 所需依赖少(只依赖接口) – 可以把成员对象动态替换为另一个类型相同的对象
Head First Design Patterns(深入浅出设计模式)-设计模式介绍
Head First Design Patterns(深入浅出设计模式)-设计模式介绍1.Welcome to Design Patterns -设计模式介绍现在我们要住进对象村(Objectville),我们刚刚开始接触设计模式…每个人都在使用它们。
一会我们将去参加Jim和Betty的星期三晚上的模式聚会!有人已经解决了你的问题。
在这章里,你将学习到为什么(和怎么样),你将学习到那些幸存下来的开发者的智慧和教训,他们都曾经历过类似的设计问题。
在我们做之前,我们将先看看设计模式的用途和好处,再看一些关键的面向对象设计原则,并且再通过一个实例了解模式的工作方式。
使用模式最好的方法就是把它们装入脑袋里,然后在你设计和现有的应用程序里找到你能够应用它们的地方。
相对于代码重用,使用模式你获得了经验的重用。
-1-从一个简单的模拟鸭子程序开始乔为一个制造非常成功的模拟鸭子池塘游戏(SimUDuck)的公司工作。
这个游戏可以展示很多种鸭子的游泳方式和呷呷叫声。
系统最初的设计者们使用了标准的面向对象技术,他们创建了一个Duck基类供所有其它类型的鸭子继承。
去年,竞争者们给公司带来了越来越多的压力。
经过历时一周在高尔夫球赛场上的集体讨论,公司的经理们都觉得该是进行一次大改革的时候了。
他们需要在下周在毛伊岛举行的股东大会上展示一些真正给人深刻印象的东西。
-2-但是我们现在需要鸭子可以飞经理们确定会飞的鸭子就是模拟器需要的用来击败其他竞争者的东西。
当然,乔的经理告诉他们,对于乔来说在一周内迅速搞定这些根本不是问题。
“毕竟”,乔的上司说,“他是一个面向对象的程序员…那些有什么难的呢?”乔想:我仅仅只需要在Duck类里增加fly()方法,然后所有其他鸭子就都可以继承它了。
现在是展示我真正的面向对象才华的时候了。
-3-但是有些事情严重错误了…乔的上司:乔,我正在股东大会上。
他们刚看完演示,很多橡皮鸭子在屏幕上四处乱飞。
这是你在开玩笑吗?…发生了什么事?乔没有注意到并不是所有Duck的子类都需要fly()方法。
Head First 设计模式学习笔记(一)
Head First 设计模式学习笔记(一)public absact class Duck { FlyBehavior flyBehavior;QuackBehavior quackBehavior; public voFlyBehavior(FlyBehavior fb) { flyBehavior = fb; public void setQuackBehavior(QuackBehavior qb) { quackBehavior = qb; void perfoQuack(){ quackBehavior.quack(); voidperformFly(){ flyBehavior.fly(); void swim(){//游泳System.out.print("游泳ing..."); abstract void display(); //展示外观 package com.ch; public interface FlyBehavior { void fly(); //飞翔动作 package com.ch; public interfaceQuackBehavior { void quack(); //叫声 package com.ch; public class FlyNoWay implements FlyBehavior{ @Override public void fly() { System.out.println("我是不会飞的鸭子"); packagecom.ch; public class FlyWithWings implements FlyBehavior{ @Override public void fly(){ System.out.println("我是会飞的鸭子"); package com.ch; public class Quack implements QuackBehavior{ @Override public void quack() { System.out.println("呱呱叫"); package com.ch; public class Squeak implementsQuackBehavior{ @Override public void quack(){ System.out.println("吱吱叫"); package com.ch; public class MallardDuck tends Duck { public MallardDuck(){ quackBehavior = new Quack(); flyBehavior = new FlyWithWings(); @Override void display(){ System.out.println("....");第1页共1页。
《HeadFirst设计模式》阅读笔记.第七章...
《HeadFirst设计模式》阅读笔记.第七章...2010-01-21《Head First设计模式》阅读笔记.第七章文章分类:Java编程1.适配器(Adapter)模式部分*OO适配器和真实世界的适配器扮演者同样的角色:将一个接口转换成另一个接口,以符合客户的期望。
*适配器(Adapter)类看起来很像命令(Command)模式中命令接口的实现类,只不过它不被作为参数传递。
Java代码1.----DuckAdapter类----2.public class DuckAdapter implements Turkey {3.private Duck duck;4.5.public DuckAdapter(Duck duck) {6.this.duck = duck;7.}8.9.public void goggle() {10.duck.quack();11.}12.13.public void fly() {14.duck.fly();15.}16.}17.------------适配器模式:将一个类的接口,转换成客户希望的另一个接口。
适配器让原本接口不兼容的类合作无间。
*适配器模式可以让客户从实现的接口解耦。
*适配器(Adapter)模式充满着良好的OO设计原则:使用对象组合,以修改的接口包装被适配者;这种做法还有额外的优点,那就是被适配者的任何子类都可以搭配着适配器使用。
*适配器(Adapter)分为“对象(Object)”适配器和“类(Class)”适配器两种。
*在类适配器中,适配器继承了目标(Target)和被适配者(Adaptee);而对象适配器中,适配器利用组合的方式将请求传送给被适配者。
*类适配器是基于多重继承实现的,因为Java不支持多重继承,因此无法做到。
*由于类适配器使用了继承的方式,所以它的优点是不需要整个实现被适配者,必要的时候还可以覆盖被适配者的行为。
Java代码1.----练习。
HeadFirst设计模式——策略模式
HeadFirst设计模式——策略模式1、继承带来的扩展和复⽤问题继承作为⾯向对象的三⼤要素(封装、继承、多态)之⼀为什么会带来问题,问题如何解决然后形成⼀种设计模式,head frist设计模式书中以鸭⼦作为例⼦讲解什么情况下继承的⽅式会带来问题。
⾸先有各种各样的鸭⼦,那么⾃然想到各种鸭⼦继承⾃⼀个⽗类:⽗类为Duck,现有绿头鸭GreenHeadDuck和红头鸭RedHeadDuckpublic abstract Class Duck{ public void quack(){} public void swin(){} public abstract void display();}publci class GreenHeadDuck:Duck{public overrid void display(){//外观绿头}}publci class ReadHeadDuck:Duck{public overrid void display(){//外观红头}}⽗类中所有鸭⼦都会呱呱叫(quack)和游泳(swin),外观却不⼀样所以display为抽象⽅法,让继承它的⼦类重写。
现在需要新增⼀种鸭⼦,但这个鸭⼦是⼀个玩具橡⽪鸭,我们按照继承的⽅式则橡⽪鸭实现代码如下publci class RubberDuck:Duck{ public override void qucak(){ //覆盖成吱吱吱叫 }public override void display(){//外观是橡⽪鸭}}因为橡⽪鸭是不会像其他鸭⼦那样叫的,所以上⾯代码我们需要重写qucak覆盖橡⽪鸭叫的⽅式可。
现在有⼀个需求,需要让鸭⼦飞起来,按照继承的⽅式我们给⽗类Duck添加 fly⽅法即可让所有鸭⼦飞起来。
但是问题出现了,橡⽪鸭是不会飞的,于是我们可以像覆盖qucak⽅法⼀样在RubberDuck中覆盖fly⽅法。
public abstract class Duck{ public void quack(){} public void swin(){} public abstract void display();public void fly(){}}publci class RubberDuck:Duck{ public override void qucak(){ //覆盖成吱吱吱叫 }public override void display(){//外观是橡⽪鸭}public override void fly(){//覆盖,什么都不做}}到这⾥我们已经发现了继承带来的问题:1、代码在多个⼦类中重复。
HeadFirst 设计模式(1)综述
设计原则2:针对接口编程,而非针对实现
接口使可插入性变得可能。
1. Client不必知道其使用对象的具体所属类。 2. 一个对象可以很容易地被(实现了相同接口的)的另 一个对象所替换。 3. 对象间的连接不必硬绑定(hardwire)到一个具体类 的对象上,因此增加了灵活性。 4. 松散藕合(loosens coupling)。 5. 增加了重用的可能性。 6. 提高了(对象)组合的机率,因为被包含对象可以是 任何实现了一个指定接口的类。
设计原则4:开-闭原则
• Bertrand Meyer
– 对象技术大师 – 法国工程院院士 – 苏黎世工学院计算机系教授 – 发明了Eiffel语言和按契约设计 (Design by Contract)的思想 – 早年参与了Z形式语言的设计 – 名著《面向对象软件构造》
可维护可扩展可复用灵活性
松耦合 高内聚. OOP: 封装,继承,多态
可维护+可扩展+可复用
松耦合 高内聚. OOP: 封装,继承,多态
设 计 模 式
封 闭 开 放 封 装 变 化 面 向 接 口 组 合 复 用 依 赖 倒 置 里 氏 法 则 迪 米 特
逻辑 。。。 物理 一致
设计原则3: 组合优先
组合(has a)比继承(is a)更好一些
设计原则3: 组合优先
• 策略模式中体现了多个设计原则
设计原则1: 封装变化
可维护+可扩展+可复用
松耦合 高内聚. OOP: 封装,继承,多态
设 计 模 式
封 闭 开 放 封 装 变 化 面 向 接 口 组 合 复 用 依 赖 倒 置 里 氏 法 则 迪 米 特
逻辑 。。。 物理 一致
设计原则2:针对接口编程,而非针对实现
《Head.First设计模式》读书笔记
《Head.First设计模式》读书笔记目录1、创建型设计模式 (1)1.1工厂方法Factory Method【类】与抽象工厂Abstract Factory【对象、chapter 4】 (1)1.2单件Singleton【chapter5、对象】 (2)2、结构型设计模式 (2)2.1适配器Adapter【chapter7、类/对象】 (2)2.2组合Composite【chapter9、对象】 (2)2.3装饰者Decorator【chapter3、对象】 (2)2.4外观Facade【chapter7、对象】 (3)2.5代理Proxy【chapter11、对象】 (3)3、行为型设计模式 (3)3.1模板方法Template Method【chapter8、类】 (3)3.2命令Command【chapter6、对象】 (3)3.3迭代器Iterator【chapter9、对象】 (4)3.4观察者Observer【chapter2、对象】 (4)3.5状态State【chapter10、对象】 (4)3.6策略Strategy【chapter1、对象】 (4)4、与设计模式相处 (5)1、创建型设计模式1.1工厂方法Factory Method【类】与抽象工厂Abstract Factory【对象、chapter 4】(1) 工厂方法Factory Method:定义:由子类决定要实例化的类是哪一个。
让类把实例化推迟到子类。
实例:拓展披萨工厂,有各地风味的加盟店。
实现:分为Product(产品类披萨)和Creator(创建者类PizzaStore)两个类层级,都有许多具体的子类,每个子类都有自己特定的实现。
相关:“依赖倒置原则Dependency Inversion Principle”【6】。
要依赖抽象,不要依赖具体类。
PizzaStore是高层组件、比萨实现是低层组件,前者依赖后者。
head first中所有的设计原则
head first中所有的设计原则在《Head First 设计模式》一书中,提到了以下几种设计原则:
1. 单一职责原则:一个类应该只有一个引起变化的原因。
也就是说,每个类应该只有一个职责,只负责一项功能。
2. 开放封闭原则:软件实体(类、模块、函数等等)应该是可以扩展的,但是不可修改。
也就是说,新的功能应该通过添加新的模块或者子类来实现,而不是修改现有的代码。
3. 里氏替换原则:如果S是T的子类,则程序中使用T类型的对象的地方都可以用S类型的对象来替换,而不会引起任何不期望的后果。
4. 接口隔离原则:客户端不应该依赖它不使用的接口。
接口隔离原则可以降低客户代码与实现细节之间的耦合度,使得客户端更加灵活和易于维护。
5. 依赖倒置原则:高层模块不应该依赖于低层模块,它们都应该依赖于抽象。
抽象不应该依赖于细节,细节应该依赖于抽象。
6. 迪米特法则:一个对象应该对其他对象保持最少的了解。
也就是说,一个对象应当尽可能少的与其他对象直接相互作用,不应该强制具体的对象直接通信,而应该使用一种规约方式(例如抽象类或接口)来进行间接通信。
7. 合成复用原则:尽量使用合成/聚合,而不是继承关系达到软件复用的目的。
以上是《Head First 设计模式》中提到的设计原则,这些原则可以帮助我们设计出更加健壮、可维护和可扩展的软件系统。
head first 设计模式
Head First 设计模式介绍Head First 设计模式是一本由埃里克·弗里曼(Eric Freeman)、伊丽沙白·弗里曼(Elisabeth Freeman)、考思温·西迪(Kathy Sierra)和贾尼特·贝茨(Bert Bates)合著的图书,该书使用了一种独特的学习方式,通过大量的图表、示例和练习来帮助读者理解和实践面向对象设计模式。
本文档将对 Head First 设计模式进行简要概述,并介绍其中涵盖的几种常见的设计模式。
设计模式概述设计模式是在软件开发过程中经常出现的问题的解决方案。
它们旨在提供一种通用的方法,帮助开发人员解决特定类型的问题。
设计模式有助于提高软件的可重用性、可维护性和可扩展性。
Head First 设计模式一书介绍了23种常见的设计模式,分为三种类型:创建型模式、结构型模式和行为型模式。
•创建型模式:这些模式关注对象的创建过程,包括如何实例化对象和配置对象的创建流程。
•结构型模式:这些模式关注对象之间的组合,以建立更大的结构,并提供对象之间的简化操作。
•行为型模式:这些模式关注对象之间的交互和通信,以实现特定的行为和协作。
以下是 Head First 设计模式中介绍的一些常见设计模式:创建型模式单例模式单例模式确保一个类只有一个实例,并提供一个全局访问点来访问该实例。
通过单例模式,我们可以限制对某个类的实例化,避免多个对象同时存在。
工厂模式工厂模式是一种创建型模式,它定义了一个创建对象的接口,但将具体的实现交给了子类来决定。
工厂模式可以通过将对象的创建和使用解耦,从而提供一种灵活的方法来创建多个对象的实例。
结构型模式适配器模式适配器模式将一个类的接口转换为客户端所期望的另一个接口,从而使两个类能够协同工作。
适配器模式适用于需要将一个类集成到另一个类中,并且不能修改原有类的情况。
装饰器模式装饰器模式允许在不改变现有对象结构的情况下,动态地添加行为。
head first讲解的设计模式
head first讲解的设计模式Head First系列是一套以轻松幽默的方式讲解技术知识的图书系列,其中也包括了对设计模式的讲解。
设计模式是软件开发中常用的一种解决问题的方法论,它提供了一套经过验证的解决方案,可以帮助开发者更好地组织和设计代码。
在Head First系列中,设计模式被分为23种,每一种设计模式都通过生动的例子和故事来解释。
这种讲解方式不仅能够提高读者的兴趣,还能够更好地理解和记忆设计模式的核心概念。
下面将简要介绍一些Head First中讲解的设计模式。
1. 策略模式(Strategy Pattern)策略模式定义了一系列算法,并将它们封装起来,使得它们可以互相替换。
这样可以让算法的变化独立于使用算法的客户端。
Head First通过一个鸭子游戏的例子来讲解策略模式的应用,读者可以通过这个例子更好地理解策略模式的概念和实现方式。
2. 观察者模式(Observer Pattern)观察者模式定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
Head First通过一个天气预报的例子来讲解观察者模式的应用,读者可以通过这个例子理解观察者模式的工作原理和实现方式。
3. 装饰者模式(Decorator Pattern)装饰者模式允许对象动态地添加新的行为,而不需要修改现有的代码。
Head First通过一个星巴克咖啡的例子来讲解装饰者模式的应用,读者可以通过这个例子理解装饰者模式如何在不修改原有代码的情况下增加新的功能。
4. 工厂模式(Factory Pattern)工厂模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。
Head First通过一个披萨店的例子来讲解工厂模式的应用,读者可以通过这个例子了解工厂模式如何将对象的创建和使用分离。
5. 单例模式(Singleton Pattern)单例模式确保一个类只有一个实例,并提供一个全局访问点。
head first设计模式
Head First设计模式介绍Head First设计模式是一本由Eric Freeman、Elisabeth Robson、Kathy Sierra和Bert Bates合著的经典书籍,它以一种有趣且易于理解的方式介绍了软件设计模式的概念和实例。
该书通过生动的插图、真实的场景和互动式的内容,帮助读者更好地理解和应用设计模式。
本文将简要介绍Head First设计模式的主要内容,并通过几个设计模式示例来展示如何应用这些模式来解决常见的软件设计问题。
设计模式概述设计模式是一套经过反复验证的、可复用的解决方案,用于解决软件设计中的常见问题。
设计模式提供了一种共享的词汇,并描述了如何将这些词汇组合成解决方案。
设计模式通常可以分为三类:创建型模式、结构型模式和行为型模式。
•创建型模式关注如何创建对象,包括简单工厂模式、工厂方法模式、抽象工厂模式、单例模式、建造者模式和原型模式。
•结构型模式关注如何组织对象,包括适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式和享元模式。
•行为型模式关注对象之间的通信和职责分配,包括模板方法模式、策略模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、状态模式、访问者模式和解释器模式。
接下来,我们将通过几个具体的设计模式示例来说明Head First设计模式的应用。
示例1:工厂方法模式工厂方法模式是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定要实例化的类是哪一个。
工厂方法模式将对象的实例化推迟到子类中,从而实现了解耦和灵活性。
public abstract class PizzaStore {public Pizza orderPizza(String type) {Pizza pizza = createPizza(type);pizza.prepare();pizza.bake();pizza.cut();pizza.box();return pizza;}protected abstract Pizza createPizza(String t ype);}在上面的代码中,我们定义了一个抽象的PizzaStore类,其中的createPizza()方法由子类来实现,用于创建具体的Pizza对象。
Head First 设计模式之命令模式(CommandPattern)
Head First 设计模式之命令模式(CommandPattern)前言:本章会将封装带入到一个全新的境界,把方法调用封装起来。
通过封装方法调用,把运算块包装成形。
调用此运算的对象不需要知道事情是如何进行的,只要知道如何使用包装形成的方法来完成它就ok了。
1 现实场景应用现在有一个遥控器,该遥控器有7个插槽需要编程,可以在每个插槽上放上不同的装置,然后用按钮控制它,这七个插槽具备各自的“开”“关”按钮,还有一个整体用的撤销按钮,会撤销最后一个按钮的动作。
1.1 创建第一个命令对象1.1.1 定义命令接口[csharp] view plain copy 在CODE上查看代码片派生到我的代码片public interfaceCommand{void Execute();}1.1.2 实现一个打开灯的命令[csharp] view plain copy 在CODE上查看代码片派生到我的代码片publicclass Light //电灯类{public void On(){System.Console.WriteLine("Light is On !");}public void Off(){System.Console.WriteLine("Light is Off !");}}public class LightOnCommand : Command//实现开灯命令{private Light light;public LightOnCommand(Light light){this.light = light;}public void Execute()light.On();}}1.1.3 使用命令对象[csharp] view plain copy 在CODE上查看代码片派生到我的代码片public class LightControl{privateCommand soft;publicvoid SetCommand(Command cmd){soft= cmd;//设置命令对象}publicvoid ButtonWasPressed(){soft.Execute();//调用命令对象的方法}}1.1.4 简单测试[csharp] view plain copy 在CODE上查看代码片派生到我的代码片LightControl lightControl = new LightControl();//模拟命令的调用者Lightlight = new Light();//创建一个电灯对象,作为命令的接收者LightOnCommand lightOnCommand = new LightOnCommand(light);//创建一个命令,并将接受者传递给它lightControl.SetCommand(lightOnCommand);//将命令传给调用者lightControl.ButtonWasPressed();//模拟触发按钮1.2 实现遥控器[csharp] view plain copy 在CODE上查看代码片派生到我的代码片public class RemoteControl{Command[] onCommands;//定义打开的命令数组Command[] offCommands; //定义关闭的命令数组public RemoteControl(){onCommands = new Command[7];offCommands = new Command[7];Command noCommand = newNoCommand();for (int i = 0; i < 7; i++){onCommands[i] = noCommand;//初始化命令数组(默认设置为无命令)offCommands[i] = noCommand;}//将命令设置到对应的控制器public void SetCommand(int index,Command onCommand, Command offCommand){onCommands[index] = onCommand;offCommands[index] = offCommand;}//触发打开控制器public void OnButtonWasPressed(int index){onCommands[index].Execute();}//触发关闭控制器public void OffButtonWasPressed(intindex){offCommands[index].Execute();}public override string ToString(){StringBuilder str = newStringBuilder();str.Append("\n------RemoteControl ------\n");for (int i = 0; i <onCommands.Length; i++){str.Append("[solt" +i + "]" + onCommands[i].GetType().FullName + " " +offCommands[i].GetType().FullName + "\n");}return str.ToString();}}1.3 实现其他控制器[csharp] view plain copy 在CODE上查看代码片派生到我的代码片//关闭电灯命令public classLightOffCommand : Command{privateLight light;publicLightOffCommand(Light light){this.light = light;}publicvoid Execute(){light.Off();}publicvoid Undo(){light.On();}}//打开电扇命令public class CeilingFanOnCommand : Command{CeilingFan ceilingFan;intpreSpeed;publicCeilingFanOnCommand(CeilingFan ceilingFan){this.ceilingFan = ceilingFan;}publicvoid Execute(){ceilingFan.On();}publicvoid Undo(){ceilingFan.Off();}}//关闭电扇命令public classCeilingFanOffCommand : Command{CeilingFan ceilingFan;publicCeilingFanOffCommand(CeilingFan ceilingFan){this.ceilingFan = ceilingFan;}publicvoid Execute(){ceilingFan.Off();}publicvoid Undo(){ceilingFan.On();}}//打开车库门命令public classGarageDoorOnCommand : Command{GarageDoor garageDoor;publicGarageDoorOnCommand(GarageDoor garageDoor){this.garageDoor= garageDoor;}publicvoid Execute(){garageDoor.On();}publicvoid Undo(){garageDoor.Off();}}//关闭车库门命令public classGarageDoorOffCommand : Command{GarageDoor garageDoor;publicGarageDoorOffCommand(GarageDoor garageDoor){this.garageDoor = garageDoor;}publicvoid Execute(){garageDoor.Off();}publicvoid Undo(){garageDoor.On();}}//打开CD命令public classStereCDOnCommand : Command{StereCDstereCD;publicStereCDOnCommand(StereCD stereCD){this.stereCD = stereCD;}publicvoid Execute(){stereCD.On();}publicvoid Undo(){stereCD.Off();}}//关闭CD命令public classStereCDOffCommand : Command{StereCDstereCD;publicStereCDOffCommand(StereCD stereCD){this.stereCD = stereCD;}publicvoid Execute(){stereCD.Off();}publicvoid Undo(){stereCD.On();}}1.4简单测试[csharp] view plain copy 在CODE上查看代码片派生到我的代码片RemoteControlremoteControl = new RemoteControl ();CeilingFan ceilingFan = newCeilingFan("Living Room");//创建电扇对象GarageDoor garageDoor = newGarageDoor();//创建车库门对象StereCD stereCD = new StereCD();//创建CD对象Light light = new Light();//创建电灯对象LightOnCommand lightOnCommand = newLightOnCommand(light);//创建开灯命令LightOffCommand lightOffCommand =new LightOffCommand(light); //创建关灯命令CeilingFanOnCommandceilingFanOn = new CeilingFanOnCommand(ceilingFan); //创建开电扇命令CeilingFanOffCommand ceilingFanOff= new CeilingFanOffCommand(ceilingFan);//创建关电扇命令GarageDoorOnCommand garageDoorOn =new GarageDoorOnCommand(garageDoor);//创建打开电扇命令GarageDoorOffCommand garageDoorOff= new GarageDoorOffCommand(garageDoor);//创建关闭电扇命令StereCDOnCommand stereCDOn = newStereCDOnCommand(stereCD);//创建打开CD命令StereCDOffCommand stereCDOff = newStereCDOffCommand(stereCD);//创建关闭CD命令remoteControl.SetCommand(0,lightOnCommand, lightOffCommand);//将电灯命令设置到对应的控制器上remoteControl.SetCommand(1,ceilingFanOn, ceilingFanOff); //将电灯命令设置到对应的控制器上remoteControl.SetCommand(2,garageDoorOn, garageDoorOff); //将车库门命令设置到对应的控制器上remoteControl.SetCommand(3,stereCDOn, stereCDOff); //将CD命令设置到对应的控制器上remoteControl.OnButtonWasPressed(0);remoteControl.OffButtonWasPressed(0);remoteControl.OnButtonWasPressed(1);remoteControl.OffButtonWasPressed(1);remoteControl.OnButtonWasPressed(2);remoteControl.OffButtonWasPressed(2);remoteControl.OnButtonWasPressed(3);remoteControl.OffButtonWasPressed(3);1.5 实现撤销命令1.5.1 修改命令接口,新增Undo()方法[csharp] view plain copy 在CODE上查看代码片派生到我的代码片public interfaceCommand{void Execute();void Undo();//新增撤销方法}1.5.2 修改命令,实现Undo方法[csharp] view plain copy 在CODE上查看代码片派生到我的代码片public ss LightOnCommand : Command{private Light light;public LightOnCommand(Light light){this.light = light;}public void Execute(){light.On();}public void Undo()//实现Undo方法{light.Off();}}其他类都依次修改1.5.3 修改RemoteControl类,新增Command对象记录上一步操作[csharp] view plain copy 在CODE上查看代码片派生到我的代码片public class RemoteControlWithUndo{Command[] onCommands;Command[] offCommands;CommandundoCommand;//创建Command对象用来记录上一步执行的命令publicRemoteControlWithUndo(){onCommands = new Command[7];offCommands = new Command[7];Command noCommand = new NoCommand();for(int i = 0; i < 7; i++){onCommands[i] = noCommand;offCommands[i] = noCommand;}undoCommand = noCommand;}……………..publicvoid OnButtonWasPressed(int index){onCommands[index].Execute();undoCommand = onCommands[index];//记录打开命令}publicvoid OffButtonWasPressed(int index){offCommands[index].Execute();undoCommand = offCommands[index];//记录关闭命令}publicvoid UndoButtonWasPressed()//执行撤销{undoCommand.Undo();}…………}1.6 宏命令让遥控器具有Party模式,即一个按键能够同步调用多个命令,这就是所谓的宏命令。
head first 设计模式
Head First 设计模式简介Head First 设计模式是一本经典的设计模式入门书籍,它以清晰的语言和丰富的图片,结合了实际案例和有趣的插图,帮助读者轻松理解和应用设计模式。
本文将介绍Head First 设计模式的概述和书中提到的一些设计模式示例。
设计模式的重要性在软件开发中,设计模式是一种经过验证的解决方案,可以帮助开发人员解决常见的设计问题。
设计模式提供了一种通用的语言,使得开发人员能够共享和交流设计思想,并且可以重用已经验证的解决方案。
设计模式分类Head First 设计模式按照不同的目标进行分类,包括创建型模式、结构型模式和行为型模式。
创建型模式创建型模式主要处理对象创建的机制,包括了单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式。
单例模式单例模式用来确保一个类只有一个实例,并且提供一个全局访问点来访问这个实例。
这在需要共享资源的情况下非常有用。
工厂模式工厂模式用来创建对象,而无需暴露对象创建的逻辑。
它通过将对象的创建委托给工厂类来实现。
抽象工厂模式抽象工厂模式提供了一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。
建造者模式建造者模式用于将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
原型模式通过复制现有对象来创建新对象,而无需耗费额外的资源。
结构型模式结构型模式主要处理对象之间的组合,包括了适配器模式、装饰者模式、代理模式、外观模式、桥接模式和组合模式。
适配器模式适配器模式用于将一个类的接口转换成客户端所期望的接口。
装饰者模式装饰者模式通过将对象包装在其他对象中来动态地为对象添加额外的行为。
代理模式代理模式提供了一个代理对象,可以控制对真实对象的访问,并可以在访问真实对象之前或之后添加额外的逻辑。
外观模式提供了一个统一的接口,用于访问子系统的一组接口。
通过使用外观模式,可以简化复杂系统的接口,使得系统更易于使用。
桥接模式桥接模式将抽象与实现进行分离,以便它们可以独立地变化。
HeadFirst设计模式(一)策略者模式
HeadFirst设计模式(⼀)策略者模式最近在看HeadFirst设计模式⼀书,作为⼀个半路出家的程序员,感觉很多东西需要学习,学习的路程中有些东西学了当时觉得理解了,但⽇常⼯作中没有使⽤到渐渐的⾃⼰就忘记了。
----------------------上⾯就是写者系列的博客的原因,主要是为了巩固知识,忘记在那个博主那边看过这么⼀句话,知识学了后总结了才变成⾃⼰的。
策略者模式----定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独⽴于使⽤算法的客户。
当然这只是理论的东西,说实话我现在都没理解这个理论是啥,下⾯我⽤代码和⽐较直观的语⾔给⼤家介绍⼀下策略者模式,希望能有所收获。
模拟情节: Joe上班的公司有⼀套鸭⼦游戏的系统:SimUDuck,游戏中有各种鸭⼦,⼀边游泳,⼀边呱呱叫。
此系统使⽤了标准的OO(⾯向对象)技术。
设计⼀个鸭⼦的超类(也就是⽗类-Duck),并让各种鸭⼦继承此超类。
此时由于需求的改变需要增加飞⾏的功能,Joe直接在超类中添加fly()⽅法:1public abstract class Duck2 {3public void quack()4 {5 Console.WriteLine("我会叫");6 }78public void swim()9 {10 Console.WriteLine("我会游泳");11 }1213public void fly()14 {15 Console.WriteLine("我会飞");16 }17public abstract void display();18 }1920public class MallardDuck : Duck21 {22public override void display()23 {24 Console.WriteLine("我是⼀只绿头鸭");25 }2627 }28public class ModelDuck : Duck29 {30public override void display()31 {32 Console.WriteLine("我是⼀只模型鸭⼦");33 }34 }35public class RedheadDuck : Duck36 {3738public override void display()39 {40 Console.WriteLine("我是⼀只红头鸭");41 }42 }4344class Program45 {46static void Main(string[] args)47 {48 Duck modelDuck=new ModelDuck();49 modelDuck.quack();50 modelDuck.display();51 modelDuck.fly();52 Console.ReadLine();53 }54 }此时问题就来了,模型鸭⼦(ModelDuck)由于也是继承于超类也具备了飞⾏的功能,显然继承在这⾥并不是⼀个很好的解决⽅案。
Head_First_设计模式
编辑推荐本书荣获2005年第十五届Jolt通用类图书震撼大奖。
本书英文影印版被《程序员》等机构评选为2006年最受读者喜爱的十大IT图书之一 。
本书趋近完美,因为它在提供专业知识的同时,仍然具有相当高的可读性。
叙述权威、文笔优美。
本书共有14章,每章都介绍了几个设计模式,完整地涵盖了四人组版本全部23个设计模式。
前言先介绍这本书的用法;第1章到第11章陆续介绍的设计模式为Strategy、Observer、Decorator、Abstract Factory、Factory Method、Singleton、Command、Adapter、Facade、Templat Method、Iterator、Composite、State、Proxy。
最后三章比较特别。
第12章介绍如何将两个以上的设计模式结合起来成为新的设计模式(例如著名的MVC模式),作者称其为复合设计模式(这是作者自创的名称,并非四人组的标准名词),第13章介绍如何进一步学习设计模式,如何发觉新的设计模式等主题,至于第14章则很快地浏览尚未介绍的设计模式,包括Bridge、Builder、Chain of Responsibility、Flyweight、Interpreter、Mediator、Memento、Prototype、Visitor。
第1章还介绍了四个OO基本概念(抽象、封装、继承、多态),而第1章到第9章也陆续介绍了九个OO原则(Principle)。
千万不要轻视这些OO原则,因为每个设计模式背后都包含了几个OO原则的概念。
很多时候,在设计时有两难的情况,这时候我们必须回归到OO原则,以方便判断取舍。
可以这么说:OO原则是我们的目标,而设计模式是我们的做法。
本书作者Eric Freeman和Elisabeth Freeman是作家、讲师和技术顾问。
Eric拥有耶鲁大学的计算机科学博士学位,Elisabath拥有耶鲁大学的计算机科学硕士学位。
Head_First design pattern 学习总结
《Head First设计模式》阅读笔记1、模式(Pattern)定义策略(Strategy)模式:定义一组算法族,分别封装起来,让各个算法之间可以相互替换。
此模式让算法的变化独立于使用算法的客户。
观察者模式:定义了对象之间的一对多依赖关系,当一个对象(主题对象)的状态改变时,它的所有依赖者(观察者对象)都会收到通知并自动更新。
装饰者模式:动态地将责任加到对象身上。
如果要扩展功能,装饰者模式提供了比继承更有弹性的替代方案。
*用静态方法定义的工厂被成为静态工厂,这样就不用使用创建对象的方法来实例化对象,使用方便。
但是这样做的缺点是无法通过继承来改变创建方法的行为。
*简单工厂不是一种设计模式,但是它比较常用。
*工厂方法用来处理对象的创建,并将这样的行为封装在子类中。
这样,客户程序中关于超类的代码就和子类对象的创建代码解耦(Decouple)了。
工厂方法的定义:abstract Product factoryMethod(String type);工厂(Factory Method Pattern)方法模式:定义了一个创建对象的接口,但是由子类来决定要实例化的类是哪一个。
它让类把实例化推迟到了子类。
抽象工厂模式:提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类。
单件(Singleton)模式:确保一个类只有一个实例,并提供一个全局访问点。
命令(Command)模式:将“请求”封装成对象,以便使用请求、队列或日志来参数化其它对象。
命令模式也支持可撤销的操作。
适配器模式:将一个类的接口,转换成客户希望的另一个接口。
适配器让原本接口不兼容的类合作无间。
外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。
外观模式定义了一个高层接口,让子系统更容易使用。
迭代器模式:提供一种顺序访问集合对象中各个元素的方法,而又不暴露其内部的表示(也就是数据结构)。
组合模式:将对象组合成树状结构来表现“整体/部分”的层级结构,让客户以一致的方式来处理个别对象以及对象组合。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
设计原则3:组合优先
• 继承复用的缺点
– 继承破坏封装,因为父类的实现细节完全暴露给子类 (白盒复用) – 父类的实现发生改变,则子类必受牵连 – 继承是静态的,不能在运行时发生改变,不灵活
设计原则3:组合优先
• 组合复用的优点
– 不破坏封装,这种复用是黑盒复用,因为成员对象的内部细 节对新对象保密 – 所需依赖少(只依赖接口) – 可以把成员对象动态替换为另一个类型相同的对象
设计原则4:开-闭原则
• 分析
– “不动众劳师”、不破坏天规就是“闭” – 收仙有道就是“开” – 招安,就是玉帝的“开-闭”原则:既让孙悟空满意, 又不必更改天庭现有的秩序
设计原则4:开-闭原则
• 分析
– 现有的天庭秩序是系统的最高抽象层 – 弼马温这个职位只是具体的实现层 – 招安的关键就是不允许更改现有的天庭秩序, 但是允许将妖猴纳入到文武百官中,从而扩展 了这一秩序的具体实现
补充 设计原则4:开-闭原则
• “开-闭”原则
– Bertrand Meyer: “Software should be open for extension, but closed for modification” – 软件应该对扩展开放, 对修改关闭
• 解释
– 在设计一个软件的时候,应当使这个软件可以在不被 修改的前提下扩展 – 已有模块,尤其是最重要的抽象层模块不能动:保证 稳定性和延续性 – 可以扩展新模块:增加新行为,保证灵活性
设计原则3:组合优先
• 组合复用的缺点
– 对象数量会增加 – 使用委托(delegation)会使得系统复杂
设计原则3:组合优先
• 例:汽车有很多种,小轿车、货车、客车,有的 车是客货两用,有的车水陆两用 • 如果使用继承来描述:
– 一旦增加新的汽车种类 或用途,都需要大量改动 原有代码
设计原则3:组合优先
设计原则2:针对接口编程,而非针对实现
接口使可插入性变得可能。
1. Client不必知道其使用对象的具体所属类。 2. 一个对象可以很容易地被(实现了相同接口的)的另 一个对象所替换。 3. 对象间的连接不必硬绑定(hardwire)到一个具体类 的对象上,因此增加了灵活性。 4. 松散藕合(loosens coupling)。 5. 增加了重用的可能性。 6. 提高了(对象)组合的机率,因为被包含对象可以是 任何实现了一个指定接口的类。
设计 模式
封 闭 开 放 封 装 变 化
策略模式
面 向 接 口
组 合 复 用
里 氏 法 则
依 赖 倒 置
迪 米 特
逻辑 。。。 物理 一致
设计原则4:开-闭原则
• Bertrand Meyer
– 对象技术大师 – 法国工程院院士 – 苏黎世工学院计算机系教授 – 发明了Eiffel语言和按契约设计 (Design by Contract)的思想 – 早年参与了Z形式语言的设计 – 名著《面向对象软件构造》
可维护可扩展可复用灵活性
松耦合 高内聚. OOP: 封装,继承,多态
设计原则1:封装可变性
识别程序中可变的特征, 并将它们与不变的特征分离开来
现实中的封装可变性
维护, 扩展, 复用?
策略模式的优点
• (1)策略模式提供了管理相关的算法族的办 法。
• (2)策略模式提供了可以替换继承关系的办 法。 • (3)使用策略模式可以避免使用多重条件转 移语句。
GOF:“考虑你的设计中什么可能会发生变化......考虑你
允许什么发生变化而不让这一变化导致重新设计” – 一种可变性不应散落在代码的很多角落 – 一种可变性不应当与另一种可变性混合在一起
能否用封装原理表述?
设计原则1:封装可变性
识别程序中可变的特征, 并将它们与不变的特征分离开来
逻辑相关,物理封装
Design Pattern (设计模式)
第一章: Strategy Pattern 策略模式
• • Wang Ying-hong Technical Consultant
• HP Technical Service
再增加新鸭?
设计原则1:封装可变性
识别程序中可变的特征, 并将它们与不变的特征分离开来
设计原则4:开-闭原则
• Strategy模式对“开-闭”原则的支持
设计原则4:开-闭原则
• 玉帝遵照“开-闭”原则维护天庭秩序
– 当年孙悟空大闹天空,向天庭发出挑战:“皇帝轮流 做,明年到我家......只教他搬出去,将天宫让与我!” – 太白金星给玉皇大帝 建议道:“降一道招安 圣旨,把他宣来上界... 与他籍名在箓... 一则不动众劳师, 二则收仙有道也。”
策略模式的缺点
• (1) 客户端必须知道所有的策略类,并自行 决定使用哪一个策略类。
• (2)策略模式造成很多的策略类, 增加了对 象的数目。 • (3)增加了通信开销
在什么情况下应当使用策略模式
• (1)如果在一个系统里面有许多类,它们之间的 区别仅在于它ቤተ መጻሕፍቲ ባይዱ的行为,那么使用策略模式可以 动态地让一个对象在许多行为中选择一种行为。 • (2)一个系统需要动态地在几种算法中选择一种。 • (3)一个系统的算法使用的数据不可以让客户端 知道。 • (4)如果一个对象有很多的行为,如果不用恰当 的模式,这些行为就只好使用多重的条件选择语 句来实现。
• 使用“组合”思路考虑问题
– “汽车”拥有某种或某些“用途” – “汽车”和“用途”独立变化,互不影响
可维护+可扩展+可复用
松耦合 高内聚. OOP: 封装,继承,多态
设 计 模 式
封 闭 开 放 封 装 变 化 面 向 接 口 组 合 复 用 依 赖 倒 置 里 氏 法 则 迪 米 特
逻辑 。。。 物理 一致
可维护+可扩展+可复用
松耦合 高内聚. OOP: 封装,继承,多态
设 计 模 式
封 闭 开 放 封 装 变 化 面 向 接 口 组 合 复 用 依 赖 倒 置 里 氏 法 则 迪 米 特
逻辑 。。。 物理 一致
设计原则3: 组合优先
组合(has a)比继承(is a)更好一些
设计原则3: 组合优先
• 策略模式中体现了多个设计原则
设计原则1: 封装变化
可维护+可扩展+可复用
松耦合 高内聚. OOP: 封装,继承,多态
设 计 模 式
封 闭 开 放 封 装 变 化 面 向 接 口 组 合 复 用 依 赖 倒 置 里 氏 法 则 迪 米 特
逻辑 。。。 物理 一致
设计原则2:针对接口编程,而非针对实现