【利用AI让知识体系化】7种结构型模式(一)

简介: 【利用AI让知识体系化】7种结构型模式

结构型模式

简介

在设计模式中,结构型模式用于描述如何将对象和类组装成较大的结构,并灵活地处理对象之间的关系。

结构型模式包括以下几种:

  1. 适配器模式:用于连接不兼容的接口,让它们能够一起工作。
  2. 装饰器模式:动态地给对象添加额外的职责。
  3. 代理模式:为其他对象提供一种代理以控制对这个对象的访问。
  4. 外观模式:为复杂系统提供简化的接口,让客户端能够更容易地使用系统。
  5. 桥接模式:将抽象和实现分离开来,使得它们可以独立地变化。
  6. 组合模式:将对象组合成树形结构以表示“整体-部分”关系,客户端可以像操作单个对象一样来操作组合对象。
  7. 享元模式:共享对象,以支持大量的细粒度对象的复用。

这些结构型模式都有助于提高系统的灵活性、可扩展性和可维护性。例如,适配器模式可以将不兼容的接口转换为兼容的接口,解决实际开发中对象之间接口不兼容的问题;装饰器模式可以动态地添加更多职责,而无需改变对象本身的代码;代理模式可以控制对对象的访问,从而实现访问权限控制等功能。

尽管结构型模式中的每个模式都是独立的,但它们也常常被组合使用。例如,装饰器模式的实现中常常会用到适配器模式,而桥接模式的实现也常常会包含组合模式的思想。熟悉结构型模式可以帮助开发者更好地理解一些经典的开源框架,并且在实际项目中设计和实现更好的软件架构。

适配器模式

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的对象之间进行合作。适配器作为两个不兼容的对象之间的转换器,将一个对象的接口,转换成另一个对象需要的接口。通过适配器模式,我们可以将客户端代码与不同的对象解耦,从而提高了代码的复用性和灵活性。

一个简单的适配器模式的例子是:我们有一个圆孔和一个圆钉,但是我们需要将这个圆钉放进一个方孔里。我们可以使用一个方形适配器,将圆钉适配成方钉,使得它能够顺利地放进方孔中。

下面是使用 JavaScript 实现的简单的适配器模式的示例:

// 需要适配的类
class RoundPeg {
  constructor(radius) {
    this.radius = radius;
  }
  getRadius() {
    return this.radius;
  }
}
// 目标类
class SquareHole {
  constructor(width) {
    this.width = width;
  }
  getWidth() {
    return this.width;
  }
  fits(peg) {
    return this.getWidth() >= peg.getRadius() * Math.sqrt(2);
  }
}
// 适配器类
class SquarePegAdapter {
  constructor(peg) {
    this.peg = peg;
  }
  getWidth() {
    return this.peg.getRadius() * Math.sqrt(2);
  }
}
// 客户端代码
const roundPeg = new RoundPeg(5);
const squareHole = new SquareHole(10);
if(squareHole.fits(roundPeg)) {
  console.log('The round peg fits into the square hole!');
} else {
  const squarePegAdapter = new SquarePegAdapter(roundPeg);
  if(squareHole.fits(squarePegAdapter)) {
    console.log('The round peg fits into the square hole!');
  } else {
    console.log('The round peg does not fit into the square hole!');
  }
}

在这个示例中,我们定义了一个需要适配的圆钉类 RoundPeg 和一个目标方孔类 SquareHole。然后我们实现了一个适配器 SquarePegAdapter,将圆钉适配成一个方形钉。在客户端代码中,我们先试图将圆钉放进方孔中。如果适配成功则输出 “The round peg fits into the square hole!”,否则我们使用 SquarePegAdapter 来适配圆钉,然后再试图将适配后的方钉放进方孔中。如果适配成功则输出 “The round peg fits into the square hole!”,否则输出 “The round peg does not fit into the square hole!”。

装饰器模式

装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许以动态的方式扩展对象的功能,同时还能保证不破坏对象原有的结构和功能。该模式使用方便的包装对象机制,就可以在运行时动态地添加、删除或更改对象的职责。

一个简单的装饰器模式的例子是:我们有一个餐厅,它提供各种餐点。我们可以为这些餐点添加各种配料,比如加入奶油、火腿等。这些配料不仅可以添加,还可以随时删除或更改。这就是装饰器模式的核心思想,它允许在运行时为对象添加功能,而不是在编译时。

下面是使用 JavaScript 实现的简单的装饰器模式的示例:

// 餐点类
class Meal {
  constructor() {
    this.price = 0;
  }
  getPrice() {
    return this.price;
  }
  setPrice(price) {
    this.price = price;
  }
  getDescription() {
    return '';
  }
}
// 配料装饰器类
class MealDecorator extends Meal {
  constructor(meal) {
    super();
    this.meal = meal;
  }
  getPrice() {
    return this.meal.getPrice() + this.price;
  }
  getDescription() {
    return this.meal.getDescription() + this.description;
  }
}
// 具体的餐点类
class Hamburger extends Meal {
  constructor() {
    super();
    this.setPrice(10);
    this.setDescription('Hamburger');
  }
}
class Pizza extends Meal {
  constructor() {
    super();
    this.setPrice(20);
    this.setDescription('Pizza');
  }
}
// 具体的配料装饰器类
class Cheese extends MealDecorator {
  constructor(meal) {
    super(meal);
    this.setPrice(5);
    this.description = ' + Cheese';
  }
}
class Bacon extends MealDecorator {
  constructor(meal) {
    super(meal);
    this.setPrice(8);
    this.description = ' + Bacon';
  }
}
// 客户端代码
let meal = new Hamburger();
console.log(meal.getDescription() + ' ' + meal.getPrice());
meal = new Cheese(meal);
console.log(meal.getDescription() + ' ' + meal.getPrice());
meal = new Bacon(meal);
console.log(meal.getDescription() + ' ' + meal.getPrice());

在这个示例中,我们定义了一个基础的餐点类 Meal 和一个装饰器类 MealDecorator。然后我们又定义了两个具体的餐点类 HamburgerPizza,以及具体的配料装饰器类 CheeseBacon。这些具体的类分别根据自己的需要来实现餐点类或者装饰器类。

在客户端代码中,我们先创建一个汉堡餐 Hamburger 的实例,然后添加一份芝士和一份培根,最后输出餐点的描述以及价格。首先输出的是 “Hamburger 10”,然后再添加芝士之后输出 “Hamburger + Cheese 15”,最后再添加培根之后输出 “Hamburger + Cheese + Bacon 23”。这样,我们就成功地使用了装饰器模式来为餐点添加配料。

代理模式

代理模式(Proxy Pattern)是一种结构型设计模式,它提供了一种代理对象来控制对另一个对象的访问。代理对象充当着客户端与另一个对象之间的中介隐藏了另一个对象的复杂性,并在不改变另一个对象的情况下,提供了一些额外的功能。

一个简单的代理模式的例子是:我们有一个图片加载类,它负责加载远程图片,并将其显示在页面中。但是,在某些情况下,我们不想直接将图片加载到页面中,而是想在用户浏览器中将它进行预加载,等到用户需要加载它时再将其显示在页面中。在这种情况下,我们可以使用代理模式来实现这一需求。

下面是使用 JavaScript 实现的简单的代理模式的示例:

// 图片加载类
class ImageLoader {
  constructor(url) {
    this.url = url;
    this.image = null;
  }
  loadImage() {
    if(!this.image) {
      this.image = new Image();
      this.image.src = this.url;
    }
    return this.image;
  }
}
// 图片预加载代理类
class ImagePreloader {
  constructor(url) {
    this.imageLoader = new ImageLoader(url);
  }
  preloadImage() {
    const image = this.imageLoader.loadImage();
    if(!image.complete) {
      image.addEventListener('load', (event) => {
        this.displayImage();
      });
    } else {
      this.displayImage();
    }
  }
  displayImage() {
    console.log('Image is ready to be displayed!');
    // 在这里将图片显示到页面中
  }
}
// 客户端代码
const imagePreloader = new ImagePreloader('http://www.example.com/image.jpg');
imagePreloader.preloadImage();

在这个示例中,我们定义了一个图片加载类 ImageLoader,它负责加载图片并返回图片对象。然后我们又定义了一个图片预加载代理类 ImagePreloader,它封装了 ImageLoader 类对象,并在图片没有完全加载时,使用 addEventListener() 方法监听 load 事件,等到图片加载完成后再将其显示到页面中。

在客户端代码中,我们创建了一个 ImagePreloader 类对象,并调用它的 preloadImage() 方法来预加载远程图片。当图片加载完成后,代理对象将自动调用 displayImage() 方法将其显示在页面中。这样,我们就成功地使用代理模式来延迟加载图片,提高了网页加载速度,提升了用户体验。


外观模式

外观模式(Facade Pattern)是一种结构型设计模式,它为复杂的子系统提供一个简单的接口,使得其易于使用。该模式隐藏了子系统的复杂性,让客户端只需要与一个简单的外观对象进行交互,而不用与子系统的每个组件进行交互,从而降低了客户端代码的复杂度和依赖性。

一个简单的外观模式的例子是:我们有一个DVD播放器,它由多个组件组成,包括电源、显示器、音频等。现在我们要设计一个外观对象,它可以控制DVD的开始、暂停和停止等操作。客户端只需要与这个简单的外观对象进行交互,而不用了解每个组件的具体实现细节。

下面是使用 JavaScript 实现的简单的外观模式的示例:

// DVD播放器电源组件类
class Power {
  constructor() {
    this.isTurnedOn = false;
  }
  turnOn() {
    this.isTurnedOn = true;
    console.log('Power is turned on');
  }
  turnOff() {
    this.isTurnedOn = false;
    console.log('Power is turned off');
  }
}
// DVD播放器显示器组件类
class Display {
  display(title) {
    console.log(`Displaying ${title}`);
  }
}
// DVD播放器音频组件类
class Audio {
  play() {
    console.log('Audio is playing');
  }
  pause() {
    console.log('Audio is paused');
  }
  stop() {
    console.log('Audio is stopped');
  }
}
// DVD播放器外观类
class DVDPlayerFacade {
  constructor() {
    this.power = new Power();
    this.display = new Display();
    this.audio = new Audio();
  }
  play(title) {
    this.power.turnOn();
    this.display.display(title);
    this.audio.play();
  }
  pause() {
    this.audio.pause();
  }
  stop() {
    this.audio.stop();
    this.power.turnOff();
  }
}
// 客户端代码
const dvdPlayer = new DVDPlayerFacade();
dvdPlayer.play('Star Wars: The Last Jedi');
dvdPlayer.pause();
dvdPlayer.stop();

在这个示例中,我们定义了一个DVD播放器的电源组件类 Power、显示器组件类 Display 和音频组件类 Audio。然后我们又定义了一个DVD播放器外观类 DVDPlayerFacade,它将这些组件进行组合,提供了一个简单的接口,使得客户端可以控制DVD的开始、暂停和停止等操作。

在客户端代码中,我们创建了一个DVD播放器外观类对象 DVDPlayerFacade,并分别调用它的 play()pause()stop() 方法来控制DVD的播放操作。这些操作对于客户端代码来说是透明的,它只需要了解这个简单的外观接口,而不需要了解具体的组件实现细节。这样,我们就成功地使用外观模式来简化了DVD播放器的操作,提高了客户端代码的可读性和可维护性。


【利用AI让知识体系化】7种结构型模式(二)https://developer.aliyun.com/article/1426101

相关文章
|
5月前
|
设计模式 人工智能 自然语言处理
【利用AI让知识体系化】简要了解面向对象编程设计(二)
【利用AI让知识体系化】简要了解面向对象编程设计
|
5月前
|
人工智能 网络协议 安全
【利用AI让知识体系化】简要了解网络七层协议(二)
【利用AI让知识体系化】简要了解网络七层协议
|
5月前
|
人工智能 网络协议 数据安全/隐私保护
【利用AI让知识体系化】简要了解网络七层协议(一)
【利用AI让知识体系化】简要了解网络七层协议
|
5月前
|
设计模式 人工智能 关系型数据库
【利用AI让知识体系化】简要了解面向对象编程设计(一)
【利用AI让知识体系化】简要了解面向对象编程设计
|
5月前
|
编解码 人工智能 前端开发
【利用AI让知识体系化】常见的移动端适配知识
【利用AI让知识体系化】常见的移动端适配知识
|
5月前
|
安全 前端开发 JavaScript
【利用AI让知识体系化】前端安全攻防知识点(二)
【利用AI让知识体系化】前端安全攻防知识点
|
5月前
|
存储 前端开发 安全
【利用AI让知识体系化】前端安全攻防知识点(一)
【利用AI让知识体系化】前端安全攻防知识点
|
5月前
|
人工智能 移动开发 前端开发
【利用AI让知识体系化】Webpack 相关配置技巧(三)
【利用AI让知识体系化】Webpack 相关配置技巧
|
5月前
|
人工智能 缓存 JavaScript
【利用AI让知识体系化】Webpack 相关配置技巧(二)
【利用AI让知识体系化】Webpack 相关配置技巧
|
5月前
|
人工智能 前端开发 JavaScript
【利用AI让知识体系化】Webpack 相关配置技巧(一)
【利用AI让知识体系化】Webpack 相关配置技巧

热门文章

最新文章