当前位置: 首页 > news >正文

百度收录网站的图片烟台网站建设方案优化

百度收录网站的图片,烟台网站建设方案优化,专业建设公司网站,城阳网站建设培训前言 作为一名合格的前端开发工程师,全面的掌握面向对象的设计思想非常重要,而“设计模式”是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的,代表了面向对象设计思想的最佳实践。正如《HeadFirst设计模式》中说的一句话&…

前言

作为一名合格的前端开发工程师,全面的掌握面向对象的设计思想非常重要,而“设计模式”是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的,代表了面向对象设计思想的最佳实践。正如《HeadFirst设计模式》中说的一句话,非常好:

知道抽象、继承、多态这些概念,并不会马上让你变成好的面向对象设计者。设计大师关心的是建立弹性的设计,可以维护,可以应付改变。

是的,很多时候我们会觉得自己已经清楚的掌握了面向对象的基本概念,封装、继承、多态都能熟练使用,但是系统一旦复杂了,就无法设计一个可维护、弹性的系统。本文将结合 《HeadFirst设计模式》书中的示例加上自己一丢丢的个人理解,带大家认识下设计模式中的第一个模式——策略模式。

策略模式

策略模式:Strategy,是指,定义一组算法,并把其封装到一个对象中。然后在运行时,可以灵活的使用其中的一个算法

模拟鸭子游戏

设计模拟鸭子游戏

一个游戏公司开发了一款模拟鸭子的游戏,所有的鸭子都会呱呱叫(quack)、游泳(swim) 和 显示(dislay) 方法。

基于面向对象的设计思想,想到的是设计一个 Duck 基类,然后让所有的鸭子都集成此基类。

class Duck {quack() {}swim() {}display() {}
}

绿头鸭(MallardDuck)和红头鸭(RedheadDuck)分别继承 Duck 类:

class MallardDuck extends Duck {quack() {console.log('gua gua');}display() {console.log('I am MallardDuck');}
}class RedheadDuck extends Duck {display() {console.log('I am ReadheadDuck');}quack() {console.log('gua gua');}
}

让所有的鸭子会飞

现在对所有鸭子提出了新的需求,要求所有鸭子都会飞。

设计者立马想到的是给 Duck 类添加 fly 方法,这样所有的鸭子都具备了飞行的能力。

class Duck {quack() {}fly() {}swim() {}display() {}
}

但是这个时候代码经过测试发现了一个问题,系统中新加的橡皮鸭(RubberDuck)也具备了飞行的能力了。这显然是不科学的,橡皮鸭不会飞,而且也不会叫,只会发出“吱吱”声。

于是,设计者立马想到了覆写 RubberDuck 类的 duckfly 方法,其中 fly 方法里面什么也不做。

class RubberDuck extends Duck {quack() {console.log('zhi zhi');}fly() {}
}

继承可能并不是最优解

设计者仔细思考了上述设计,提出了一个问题:如果后续新增了更多类型的鸭子,有的鸭子既不会飞又不会叫怎么办呢?难道还是继续覆写 fly 或者 quack 方法吗?

显然,集成不是最优解。

经过一番思索,设计者想到了通过接口来优化设计。

设计两个接口,分别是 FlableQuackable 接口。

interface Flyable {fly(): void;
}interface Quackable {quack(): void;
}

这样,只有实现了 Flyable 的鸭子才能飞行,实现了 Quackable 的鸭子才能说话。

class MallardDuck implements Flayable, Quackable {fly() {}quack() {}
}

通过接口虽然可以限制鸭子的行为,但是每个鸭子都要检查一下是否需要实现对应的接口,鸭子类型多起来之后是非常容易出错的,同时,通过接口的方式虽然限制了鸭子的行为,但是代码量却没有减少,每个鸭子内部都要重复实现fly和quack的代码逻辑。

分开变化和不变化的部分

下面开始介绍我们的第一个设计原则:

找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

Duck 类中,quackfly 是会随着鸭子的不同而改变的,而 swim 和 display 是每个鸭子都不变的。因此,这里可以运用第一个设计原则,就是分开变化和不变化的部分。

面向接口编程,而不是针对实现编程

为了更好的设计我们的代码,现在介绍第二个设计原则:

针对接口编程,而不是针对实现编程。

针对接口编程的真正含义是针对超类型编程(抽象类或者接口),它利用了多态的特性。

在针对接口的编程中,一个变量声明的类型应该是一个超类型,超类型强调的是它与它的所有派生类共有的“特性”。

针对实现编程。

比如:

interface Animal {void makeSound();
}class Dog implements Animal {public void makeSound() {bark();}public void bark() {// 汪汪叫}
}Dog d = new Dog();
d.bark();

因为 d 的类型是 Dog,是一个具体的类,而不是抽象类,并且 bark 方法是 Dog 上特有的,不是共性。

针对接口编程。

Animal a = new Dog();
a.makeSound();

变量 a 的类型是 Animal,是一个抽象类型,而不是一个具体类型。此时 a 调用 makeSound 方法,代表的是所有的 Animal 都能进行的一种操作。

现在我们接着之前的思路,将鸭子的 flyquack 两个行为变为两个接口 FlyBehaviorQuackBehavior。所有的鸭子不直接实现这两个接口,而是有专门的行为类实现这两个接口。

interface FlyBehavior {fly(): void;
}interface QuackBehavior {quack(): void;
}

行为类来实现接口:

// 实现了所有可以飞行的鸭子的动作
class FlyWithWings implements FlyBehavior {fly(): void {console.log('I can fly with my wings !');}
}
// 实现了所有不会飞行的鸭子的动作
class FlyNoWay implements FlyBehavior {fly(): void {console.log('I can not fly !');}
}
// 实现了所有坐火箭飞行的鸭子的动作
class FlyRocketPowered implements FlyBehavior {fly(): void {console.log('I can fly with a rocket !');}
}
// 实现了橡皮鸭的吱吱叫声
class Squeak implements QuackBehavior {quack(): void {console.log('zhi zhi !');}
}
// 实现了哑巴鸭的叫声
class MuteQuack implements QuackBehavior {quack(): void {console.log();}
}

这样做有个好处:

  1. 鸭子的行为可以被复用,因为这些行为已经与鸭子本身无关了。
  2. 我们可以新增一些行为,不会担心影响到既有的行为类,也不会影响有使用到飞行行为的鸭子类。

整合鸭子的行为

现在鸭子的所有的行为需要被整合在一起,需要委托给别人处理。

继续改造 Duck 类。

abstract class Duck {flyBehavior: FlyBehavior;quackBehavior: QuackBehavior;constructor(flyBehavior: FlyBehavior, quackBehavior: QuackBehavior) {this.flyBehavior = flyBehavior;this.quackBehavior = quackBehavior;}public performFly(): void {this.flyBehavior.fly();}public performQuack():void {this.quackBehavior.quack();}public setFlyBehavior(flyBehavior: FlyBehavior) {this.flyBehavior = flyBehavior;}public abstract display(): void;public swim() {console.log('all ducks can swim !');}
}

在鸭子类内部定义两个变量,类型分别为 FlyBehaviorQuackBehavior 的接口类型,声明为接口类型方便后续通过多态的方式设置鸭子的行为。移除鸭子类中的 flyquack 方法,因为这两个方法已经被分离到 fly 行为类和 quack 行为类中了。

通过 performQuack 方法来调用鸭子的行为,setFlyBehavior 方法来动态修改鸭子的行为。

所有的鸭子集成 Duck 类:

// 绿头鸭
class MallardDuck extends Duck {constructor() {super(new FlyWithWings(), new Quack());}display() {console.log('I am mallard duck !');}
}// 模型鸭
class ModelDuck extends Duck {constructor() {super(new FlyNoWay(), new MuteQuack());}public display(): void {console.log('I am model duck !');}
}

在鸭子的构造函数中调用父类的构造函数,初始化鸭子的行为。

测试鸭子游戏

class Test {duck: Duck;constructor() {this.duck = new MallardDuck();}setPerformFly() {this.duck.setFlyBehavior(new FlyRocketPowered());}quack() {this.duck.performQuack();}fly() {this.duck.performFly();}
}const test = new Test();test.fly();
test.quack();test.setPerformFly();test.fly();

通过 setFlyBehavior 可以动态的改变鸭子的行为,是鸭子具备坐火箭飞行的能力。

多用组合,少用集成

从上面的例子就可以看出,每一个鸭子都有一个 FlyBehaviorQuackBehavior,让鸭子(Duck 类)将飞行和呱呱叫委托它代为处理。

当你将两个类结合起来使用,这就是组合(composition)。这种做法和继承不同的地方在于,鸭子的行为不是继承而来,而是和使用的行为对象组合而来的。也就是我们要介绍的第三个设计原则:

多用组合,少用继承

策略模式的设计步骤

  1. 定义一个接口,接口中声明各个算法所共有的操作
interface Strategy {execute(): void;
} 
  1. 定义一系列的策略,并且在遵循 Strategy 接口的基础上实现算法
class StrategyA implements Strategy {execute() {console.log('I am StrategyA'); // 算法 A}
}class StrategyB implements Strategy {execute() {console.log('I am StrategyB'); // 算法 B}
}
  1. 定义一个上下文 Context 类,在 Context 类中维护指向某个策略对象的引用,在构造函数中来接收策略类,同时还可以通过 setStrategy 在运行时动态的切换策略类,Context 类通过 setStrategy 来将具体的工作委派给策略对象。这里的 Context 类也可以作为一个基类被具体的实现类所继承,就相当于上文鸭子游戏中介绍的 Duck 类,可以被 MallardDuck、ReadheadDuck 等继承。
class Context {private strategy: Strategy;constructor(stategy: Stategy) {this.stategy = Stategy;}executeStrategy() {this.stragegy.execute();}setStrategy(stategy: Stategy) {this.stategy = stategy;}
}
  1. 创建客户端类,客户端代码会根据条件来选择具体的策略。
class Application {stragegy: Stragegy;constructor(stragegy: Stragegy) {this.stragegy = stragegy;}setCondition(condition) {if (condition === 'conditionA') {stragegy.setStrategy(new StrategyA());}if (condition === 'conditionB') {stragegy.setStrategy(new StrategyB());}}execute() {this.stragegy.execute();}
}const app = new Application();app.setCondition('conditionB');
app.execute();

策略模式结构图:
在这里插入图片描述

策略模式的使用场景

当我们在设计代码的时候,想使用对象中各种不同的算法变体,并希望能在运行时切换算法时, 可以考虑使用策略模式。

参考

源代码地址

  1. 针对接口编程,而不是针对实现编程
  2. 策略模式
  3. 《HeadFirst设计模式》
http://www.yayakq.cn/news/599232/

相关文章:

  • 综合网站设计国外网站用什么dns好
  • 哪里有零基础网站建设教学wordpress当面付
  • 网站要怎么运营什么网站流量多
  • 农产品电子商务网站开发wordpress底部居中
  • 建站之星做的网站如何导出晋城建设网站
  • 做排名的网站哪个好网页微博超话签到
  • 公司网站维护建设费入什么科目org域名为什么禁止备案
  • 营销网站建设的规则双公示网站专栏建设
  • 网页版传奇世界什么组合最好谷歌seo运营
  • cod单页建站工具青岛响应式网站设计
  • 四大免费网站域名查询服务器
  • wordpress做单页销售网站咸阳网
  • 电子商务网站建设的方法怎么看网站是否被收录
  • 临沂企业做网站pc端网站建设电话
  • pic cms图片网站管理系统手机版北京定制网站公司
  • 网站建设网络营销文章wordpress 翻页设置
  • 宝宝投票网站怎么做网站建设 上美天空
  • 所有网站收录入口水果店推广营销方案
  • 分栏型网站建立公司网站视频
  • 南昌金启网站建设怎么制作自己的签名
  • 房产中介网站建设模板企业网页制作公司青岛
  • 无锡网站建设网简述建设一个网站的一般过程
  • 机房建设网站泉州找工作网站
  • 郑州网站建设口碑好wordpress加载中
  • 退役厅网站建设中标公告双语网站建设定制开发
  • 如何做网站宣传自己大岭山镇做网站
  • 提供网站建设课程代码绵阳市住房 和城乡建设局网站
  • 长春火车站出入最新规定营销网站制作费用
  • 上海h5网站开发常德车管所网站
  • 创世网站人力资源公司外包