各位靓仔靓女们,今天咱们来聊点儿有意思的,关于JavaScript里的策略模式和工厂模式,这两个家伙就像是武林高手,一个擅长见招拆招,动态选择算法;另一个则像个神奇的炼丹炉,专门负责生产各种对象。准备好了吗?咱们这就开讲!
一、策略模式:我的算法我做主!
想象一下,你是一家电商平台的后台工程师,现在要实现一个促销活动,根据用户的不同会员等级,提供不同的折扣。如果用传统的if...else
或者switch
来处理,代码会变成这样:
function calculateDiscount(price, memberLevel) {
if (memberLevel === '普通会员') {
return price * 0.95; // 95折
} else if (memberLevel === '黄金会员') {
return price * 0.9; // 9折
} else if (memberLevel === '铂金会员') {
return price * 0.8; // 8折
} else {
return price; // 没有折扣
}
}
console.log(calculateDiscount(100, '普通会员')); // 95
console.log(calculateDiscount(100, '黄金会员')); // 90
console.log(calculateDiscount(100, '铂金会员')); // 80
console.log(calculateDiscount(100, '游客')); // 100
这段代码看起来没什么问题,但是如果以后会员等级增加,或者折扣策略发生变化,你就需要不断地修改这个函数,代码会变得越来越臃肿,维护起来也相当麻烦。这就像在武侠小说里,你只会一套拳法,遇到不同的敌人,只能用同一招,很容易被对方摸清套路。
这时候,策略模式就派上用场了。策略模式的核心思想是:定义一系列的算法,并将每一个算法封装起来,使它们可以相互替换。策略模式让算法独立于使用它的客户而变化。
简单来说,就是把不同的折扣策略分别封装成独立的类,然后根据用户的会员等级,动态地选择使用哪个折扣策略。
// 定义折扣策略接口
class DiscountStrategy {
calculate(price) {
throw new Error("calculate() method must be implemented.");
}
}
// 普通会员折扣策略
class NormalMemberDiscount extends DiscountStrategy {
calculate(price) {
return price * 0.95;
}
}
// 黄金会员折扣策略
class GoldMemberDiscount extends DiscountStrategy {
calculate(price) {
return price * 0.9;
}
}
// 铂金会员折扣策略
class PlatinumMemberDiscount extends DiscountStrategy {
calculate(price) {
return price * 0.8;
}
}
// 环境类,负责选择使用哪个策略
class DiscountContext {
constructor(strategy) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
calculateDiscount(price) {
return this.strategy.calculate(price);
}
}
// 使用策略模式
const normalDiscount = new NormalMemberDiscount();
const goldDiscount = new GoldMemberDiscount();
const platinumDiscount = new PlatinumMemberDiscount();
const context = new DiscountContext(normalDiscount); // 初始策略为普通会员
console.log(context.calculateDiscount(100)); // 95
context.setStrategy(goldDiscount); // 切换到黄金会员策略
console.log(context.calculateDiscount(100)); // 90
context.setStrategy(platinumDiscount); // 切换到铂金会员策略
console.log(context.calculateDiscount(100)); // 80
在这个例子中,我们定义了一个DiscountStrategy
接口,然后分别实现了NormalMemberDiscount
、GoldMemberDiscount
和PlatinumMemberDiscount
三个类,它们分别代表了不同的折扣策略。DiscountContext
类则负责根据用户的会员等级,动态地选择使用哪个折扣策略。
这样做的好处是:
- 代码更易于维护: 当需要添加新的折扣策略时,只需要创建一个新的类,实现
DiscountStrategy
接口即可,不需要修改现有的代码。 - 代码更具有扩展性: 可以随时切换不同的折扣策略,而不会影响到其他代码。
- 代码更具有可读性: 不同的折扣策略被封装在不同的类中,代码结构更加清晰。
策略模式就像学会了十八般武艺,遇到不同的敌人,就可以选择不同的招式,轻松应对。
策略模式的核心要点:
- 定义一个策略接口(
DiscountStrategy
)。 - 创建具体的策略类,实现策略接口(
NormalMemberDiscount
,GoldMemberDiscount
,PlatinumMemberDiscount
)。 - 创建一个环境类,持有策略接口的引用,并提供设置策略的方法(
DiscountContext
)。
策略模式的适用场景:
- 一个类有很多行为,而且这些行为需要在运行时动态地选择。
- 需要使用不同的算法来解决同一问题。
- 需要避免使用大量的
if...else
或者switch
语句。
二、工厂模式:对象的流水线生产!
现在,我们来聊聊工厂模式。想象一下,你是一家汽车工厂的老板,你需要生产各种类型的汽车,比如轿车、SUV、跑车等等。如果每次需要生产一辆汽车,都要自己手动组装,那效率也太低了。
这时候,工厂模式就派上用场了。工厂模式的核心思想是:定义一个创建对象的接口,让子类决定实例化哪一个类。工厂模式让类的实例化延迟到子类。
简单来说,就是把创建对象的任务交给工厂来完成,你只需要告诉工厂需要什么类型的对象,工厂就会自动帮你创建出来。
// 定义汽车接口
class Car {
constructor(model) {
this.model = model;
}
drive() {
console.log(`Driving a ${this.model}`);
}
}
// 轿车类
class Sedan extends Car {
constructor() {
super('Sedan');
}
}
// SUV类
class SUV extends Car {
constructor() {
super('SUV');
}
}
// 跑车类
class SportsCar extends Car {
constructor() {
super('SportsCar');
}
}
// 工厂类
class CarFactory {
createCar(type) {
switch (type) {
case 'sedan':
return new Sedan();
case 'suv':
return new SUV();
case 'sportsCar':
return new SportsCar();
default:
throw new Error('Invalid car type.');
}
}
}
// 使用工厂模式
const factory = new CarFactory();
const sedan = factory.createCar('sedan');
sedan.drive(); // Driving a Sedan
const suv = factory.createCar('suv');
suv.drive(); // Driving a SUV
const sportsCar = factory.createCar('sportsCar');
sportsCar.drive(); // Driving a SportsCar
在这个例子中,我们定义了一个Car
接口,然后分别实现了Sedan
、SUV
和SportsCar
三个类,它们分别代表了不同类型的汽车。CarFactory
类则负责根据传入的类型,创建对应的汽车对象。
这样做的好处是:
- 代码更易于维护: 当需要添加新的汽车类型时,只需要创建一个新的类,继承
Car
接口,然后在CarFactory
中添加对应的创建逻辑即可,不需要修改现有的代码。 - 代码更具有扩展性: 可以随时添加新的汽车类型,而不会影响到其他代码。
- 代码更具有可读性: 创建对象的逻辑被封装在
CarFactory
中,代码结构更加清晰。 - 解耦: 客户端代码不需要知道具体的对象创建细节,只需要知道工厂接口即可。
工厂模式就像一条流水线,只需要告诉它你需要什么,它就能帮你生产出来,省时省力。
工厂模式的核心要点:
- 定义一个抽象产品接口(
Car
)。 - 创建具体的产品类,实现抽象产品接口(
Sedan
,SUV
,SportsCar
)。 - 创建一个工厂类,根据传入的参数,创建对应的产品对象(
CarFactory
)。
工厂模式的适用场景:
- 需要创建一系列相关的对象。
- 客户端代码不需要知道具体的对象创建细节。
- 需要解耦客户端代码和具体的产品类。
三、策略模式 vs 工厂模式:哥俩好,一起走!
策略模式和工厂模式都是常用的设计模式,它们可以单独使用,也可以结合使用,以解决更复杂的问题。
特性 | 策略模式 | 工厂模式 |
---|---|---|
目的 | 动态选择算法 | 创建对象 |
重点 | 封装算法,使算法可以相互替换 | 封装对象的创建过程,解耦客户端和具体类 |
参与者 | 策略接口,具体策略类,环境类 | 抽象产品接口,具体产品类,工厂类 |
适用场景 | 一个类有很多行为,需要在运行时动态选择 | 需要创建一系列相关的对象 |
修改 | 添加新的策略,只需要创建新的策略类 | 添加新的产品,只需要创建新的产品类和修改工厂类 |
举个例子,我们可以将策略模式和工厂模式结合起来,创建一个更加灵活的折扣系统。
// 定义折扣策略接口
class DiscountStrategy {
calculate(price) {
throw new Error("calculate() method must be implemented.");
}
}
// 普通会员折扣策略
class NormalMemberDiscount extends DiscountStrategy {
calculate(price) {
return price * 0.95;
}
}
// 黄金会员折扣策略
class GoldMemberDiscount extends DiscountStrategy {
calculate(price) {
return price * 0.9;
}
}
// 铂金会员折扣策略
class PlatinumMemberDiscount extends DiscountStrategy {
calculate(price) {
return price * 0.8;
}
}
// 折扣策略工厂
class DiscountStrategyFactory {
createStrategy(memberLevel) {
switch (memberLevel) {
case '普通会员':
return new NormalMemberDiscount();
case '黄金会员':
return new GoldMemberDiscount();
case '铂金会员':
return new PlatinumMemberDiscount();
default:
return null; // 或者返回一个默认的策略
}
}
}
// 环境类,负责选择使用哪个策略
class DiscountContext {
constructor(factory, memberLevel) {
this.strategy = factory.createStrategy(memberLevel);
if (!this.strategy) {
throw new Error("Invalid member level.");
}
}
calculateDiscount(price) {
return this.strategy.calculate(price);
}
}
// 使用策略模式和工厂模式
const factory = new DiscountStrategyFactory();
const context = new DiscountContext(factory, '黄金会员');
console.log(context.calculateDiscount(100)); // 90
const context2 = new DiscountContext(factory, '铂金会员');
console.log(context2.calculateDiscount(100)); // 80
在这个例子中,我们使用工厂模式来创建不同的折扣策略,然后使用策略模式来动态地选择使用哪个折扣策略。这样做的好处是:
- 代码更加灵活:可以根据不同的会员等级,动态地创建不同的折扣策略。
- 代码更加可扩展:可以随时添加新的会员等级和对应的折扣策略,而不需要修改现有的代码。
- 代码更加易于维护:创建折扣策略的逻辑被封装在
DiscountStrategyFactory
中,代码结构更加清晰。
四、总结:掌握武功秘籍,笑傲江湖!
好了,今天的讲座就到这里了。我们学习了策略模式和工厂模式,它们就像是JavaScript中的武功秘籍,掌握了它们,你就可以编写出更加灵活、可扩展、易于维护的代码,在编程的世界里笑傲江湖!
记住,设计模式不是银弹,不要为了使用而使用。只有在合适的场景下,才能发挥出它们真正的威力。
希望今天的讲座对大家有所帮助,咱们下次再见!