又称门面模式,外观模式外观模式提供了一个统一的接口,用来访问子系统中的一群接口,定义一组高层接口让子系统更易用。
外观模式的优点非常显而易见,对客户屏蔽了内部系统实现,客户的接入成本大大降低,耦合度也变得简单。并且,子系统的变更,对客户的影响也降低,虽然用户也需要修改代码,但是大多时候只需要修改外观即可。同时,外观模式虽然提供了一个统一的入口,但并不妨碍用户直接使用子系统,使用更加复杂的功能。当然,凡事有利必有弊,外观设计模式存在什么问题呢?虽然外观模式提供了一个入口,但是并不能阻止业务方直接调用子系统,这样可能会给人一种感觉,业务方一定是这么用的,不会产生 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!"); } } }}
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中文网其他相关文章!