首页 >web前端 >js教程 >【设计模式】javascript 外观模式的应用和实践

【设计模式】javascript 外观模式的应用和实践

大鹏
大鹏原创
2020-08-11 16:19:58266浏览

定义

又称门面模式,外观模式外观模式提供了一个统一的接口,用来访问子系统中的一群接口,定义一组高层接口让子系统更易用。

适用场景

外观模式的优点非常显而易见,对客户屏蔽了内部系统实现,客户的接入成本大大降低,耦合度也变得简单。并且,子系统的变更,对客户的影响也降低,虽然用户也需要修改代码,但是大多时候只需要修改外观即可。同时,外观模式虽然提供了一个统一的入口,但并不妨碍用户直接使用子系统,使用更加复杂的功能。当然,凡事有利必有弊,外观设计模式存在什么问题呢?虽然外观模式提供了一个入口,但是并不能阻止业务方直接调用子系统,这样可能会给人一种感觉,业务方一定是这么用的,不会产生 bug,从而让人麻痹,所以,使用外观模式,同时也要对子系统做好保护。其次,外观模式实际上违背了设计模式中的开闭原则,如果我们要修改业务逻辑,常常业务方也需要进行代码修改。那么,什么样的情况下适合使用外观模式呢?如果我们的调用方用到的场景都是一样的,但我们的子系统又非常复杂,我们可以考虑封一个外观,让业务方更容易接入。

解决易用性问题。解决复杂系统的易用性问题是外观模式的最主要应用场景。还有当需要分离客户程序和服务程序的时候,使用外观模式提高子系统的独立性和可移植性。当需要构建一个层次结构的子系统,使用外观模式定义每一层的入口点。

案例

下名是一个外观模式的案例,提供借鉴和参考。

  • 复杂的内部实现类
xclass FetchMusic {  get resources() {    return [      { id: 1, title: "The Fragile" },      { id: 2, title: "Alladin Sane" },      { id: 3, title: "OK Computer" },    ];  }  fetch(id) {    return this.resources.find((item) => item.id === id);  }}class GetMovie {  constructor(id) {    return this.resources.find((item) => item.id === id);  }  get resources() {    return [      { id: 1, title: "Apocalypse Now" },      { id: 2, title: "Die Hard" },      { id: 3, title: "Big Lebowski" },    ];  }}const getTvShow = function (id) {  const resources = [    { id: 1, title: "Twin Peaks" },    { id: 2, title: "Luther" },    { id: 3, title: "The Simpsons" },  ];  return resources.find((item) => item.id === id);};const booksResource = [  { id: 1, title: "Ulysses" },  { id: 2, title: "Ham on Rye" },  { id: 3, title: "Quicksilver" },];
  • 外观类:为内部类建立简洁统一的外观接口
xxxxxxxxxxconst TYPE_MUSIC = "music";const TYPE_MOVIE = "movie";const TYPE_TV = "tv";const TYPE_BOOK = "book";class CultureFacade {  constructor(type) {    this.type = type;  }  _findMusic(id) {    const db = new FetchMusic();    return db.fetch(id);  }  _findMovie(id) {    return new GetMovie(id);  }  _findTVShow(id) {    return getTvShow(id);  }  _findBook(id) {    return booksResource.find((item) => item.id === id);  }  get _error() {    return { status: 404, error: `No item with this id found` };  }  _tryToReturn(func, id) {    const result = func.call(this, id);    return new Promise((ok, err) =>      !!result && JSON.stringify(result) !== "{}"        ? ok(result)        : err(this._error)    );  }  get(id) {    switch (this.type) {      case TYPE_MUSIC: {        return this._tryToReturn(this._findMusic, id);      }      case TYPE_MOVIE: {        return this._tryToReturn(this._findMovie, id);      }      case TYPE_TV: {        return this._tryToReturn(this._findTVShow, id);      }      case TYPE_BOOK: {        return this._tryToReturn(this._findBook, id);      }      default: {        throw new Error("No type set!");      }    }  }}
  • 客户调用:不管 music、movies、tv、book 内部子系统是怎么样的,都可以用同样的方式调用实现。
xxxxxxxxxxconst music = new CultureFacade(TYPE_MUSIC);music  .get(1)  .then((data) => console.log(data))  .catch((e) => console.error(e));const movies = new CultureFacade(TYPE_MOVIE);movies  .get(2)  .then((data) => console.log(data))  .catch((e) => console.log(e));const tv = new CultureFacade(TYPE_TV);tv.get(3)  .then((data) => console.log(data))  .catch((e) => console.log(e));const book = new CultureFacade(TYPE_BOOK);book  .get(4)  .then((data) => console.log(data))  .catch((e) => console.log(e));const weChat = new CultureFacade("WeChat");weChat  .get(1)  .then((data) => console.log(data))  .catch((e) => console.log(e));

总结

外观模式随处可见,也不难理解,现在多数公司使用微服务的开发模式,外观模式正好契合这样的开发模式。完成接口设计,就相当于完成了一半的开发任务。只要接口设计得好,那代码就差不到哪里去。接口粒度设计得太大,太小都不好。太大会导致接口不可复用,太小会导致接口不易用。在实际的开发中,接口的可复用性和易用性需要“微妙”的权衡。尽量保持接口的可复用性,但针对特殊情况,允许提供冗余的门面接口,来提供更易用的接口。

以上是【设计模式】javascript 外观模式的应用和实践的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn