外观模式

外观模式是一种结构类型的代码设计模式之一,其目的是提供一个简单的接口或门面(客户端视角的“外观”),使复杂的子系统或类更易于使用。它通过封装子系统中的一组接口,并提供一个统一的接口,简化了对子系统的操作。

模式实例代码

使用Go语言实现外观模式的示例代码:

package main

import "fmt"

// SubsystemA 是子系统A
type SubsystemA struct{}

func (s *SubsystemA) MethodA() {
    fmt.Println("SubsystemA: MethodA")
}

// SubsystemB 是子系统B
type SubsystemB struct{}

func (s *SubsystemB) MethodB() {
    fmt.Println("SubsystemB: MethodB")
}

// Facade 是外观
type Facade struct {
    subsystemA *SubsystemA
    subsystemB *SubsystemB
}

func NewFacade() *Facade {
    return &Facade{
        subsystemA: &SubsystemA{},
        subsystemB: &SubsystemB{},
    }
}

// Execute 执行操作
func (f *Facade) Execute() {
    f.subsystemA.MethodA()
    f.subsystemB.MethodB()
}

func main() {
    facade := NewFacade()
    facade.Execute()
}

上述代码中,SubsystemA和SubsystemB是两个子系统,它们分别实现了不同的方法。Facade是外观,它封装了SubsystemA和SubsystemB,提供了一个统一的接口Execute()来执行操作。通过外观模式,客户端只需与外观对象交互,而无需直接与子系统进行交互,从而简化了操作的复杂性。在示例代码中,客户端只需要创建外观对象并调用Execute()方法即可完成操作。

外观模式代码扩展性

考虑到代码的未来的扩展性,外观对象本身通常是保持不变的,不应该随着子系统的变化而频繁修改。外观模式充当了客户端和子系统之间的中介,隐藏了子系统的复杂性,客户端只需与外观对象进行交互。

如果后续需要扩展或修改子系统中的某个部分,可以通过以下方式来实现:

  1. 添加新的子系统:如果需要添加新的功能或子系统,可以创建一个新的子系统,并在外观对象中添加相应的方法,将新的子系统集成到外观中。这样客户端仍然只需要与外观对象进行交互,而不需要关心新的子系统的具体实现。
  2. 修改子系统的行为:如果需要修改子系统的行为,可以直接在子系统内部进行修改,而不会影响外观对象或客户端的代码。外观对象仅仅是对子系统的调用进行封装,修改子系统的行为不会改变外观对象的接口。
  3. 继承和重写:可以通过继承外观对象的方式来扩展或修改外观对象的行为。通过创建一个新的子类,并重写需要修改的方法,可以实现对外观对象行为的定制。这种方式可以支持对外观对象的扩展和灵活性。

总之,通过保持外观对象的稳定性和封装性,可以更容易地扩展和修改子系统,同时确保客户端的代码不需要修改。

比如未来需要添加新的子系统C时,可以按照以下步骤对外观模式进行扩展:
首先,在现有的代码基础上创建一个新的子系统C:

// 新增子系统C
type SubsystemC struct{}

func (s *SubsystemC) MethodC() {
    fmt.Println("SubsystemC: MethodC")
}

然后,在外观对象中添加对子系统C的集成和方法调用:

// Facade 是外观
type Facade struct {
    subsystemA *SubsystemA
    subsystemB *SubsystemB
    subsystemC *SubsystemC    //扩展
}

func NewFacade() *Facade {
    return &Facade{
        subsystemA: &SubsystemA{},
        subsystemB: &SubsystemB{},
        subsystemC: &SubsystemC{},  //扩展
    }
}

// Execute 执行操作
func (f *Facade) Execute() {
    f.subsystemA.MethodA()
    f.subsystemB.MethodB()
    f.subsystemC.MethodC()    //扩展
}

现在,外观对象就包含了子系统C,并在Execute()方法中调用了SubsystemC的方法。

客户端使用代码保持不变,仍只需创建外观对象并调用Execute()方法,即可同时调用子系统A、B和C的相应方法,完成操作:

// 客户端操作保持不变
func main() {
    facade := NewFacade()
    facade.Execute()
}

与中介者模式的不同

外观模式和中介者模式的确有一些相似之处,但它们的主要目的和实现方式有所不同。

外观模式的主要目的是简化客户端与复杂子系统之间的交互,提供一个统一的接口或门面,隐藏子系统的复杂性。外观模式通过封装子系统,使得客户端可以更方便地使用子系统的功能,但客户端仍然直接与外观对象进行交互。

中介者模式的主要目的是减少对象之间的直接耦合,将对象间的交互通过一个中介对象进行协调。中介者模式通过将对象间的通信集中到一个中介对象中,从而降低了对象间的依赖关系。对象不再直接相互引用,而是通过中介者对象来进行通信。

以下是一个使用Go语言实现外观模式和中介者模式进行对比的示例代码:

// 外观模式示例

// SubsystemA 是子系统A
type SubsystemA struct{}

func (s *SubsystemA) MethodA() {
    fmt.Println("SubsystemA: MethodA")
}

// SubsystemB 是子系统B
type SubsystemB struct{}

func (s *SubsystemB) MethodB() {
    fmt.Println("SubsystemB: MethodB")
}

// Facade 是外观
type Facade struct {
    subsystemA *SubsystemA
    subsystemB *SubsystemB
}

func NewFacade() *Facade {
    return &Facade{
        subsystemA: &SubsystemA{},
        subsystemB: &SubsystemB{},
    }
}

func (f *Facade) Execute() {
    f.subsystemA.MethodA()
    f.subsystemB.MethodB()
}

// 中介者模式示例

// Mediator 是中介者
type Mediator struct {
    colleagueA *ColleagueA
    colleagueB *ColleagueB
}

func NewMediator() *Mediator {
    return &Mediator{}
}

func (m *Mediator) SetColleagueA(colleagueA *ColleagueA) {
    m.colleagueA = colleagueA
}

func (m *Mediator) SetColleagueB(colleagueB *ColleagueB) {
    m.colleagueB = colleagueB
}

func (m *Mediator) CoordinateA() {
    // 协调逻辑
    fmt.Println("Mediator: Coordinate A")
    m.colleagueB.ActionB()
}

func (m *Mediator) CoordinateB() {
    // 协调逻辑
    fmt.Println("Mediator: Coordinate B")
    m.colleagueA.ActionA()
}

// ColleagueA 是同事A
type ColleagueA struct {
    mediator *Mediator
}

func NewColleagueA(mediator *Mediator) *ColleagueA {
    return &ColleagueA{mediator: mediator}
}

func (c *ColleagueA) ActionA() {
    fmt.Println("ColleagueA: Action A")
    c.mediator.CoordinateA()
}

// ColleagueB 是同事B
type ColleagueB struct {
    mediator *Mediator
}

func NewColleagueB(mediator *Mediator) *ColleagueB {
    return &ColleagueB{mediator: mediator}
}

func (c *ColleagueB) ActionB() {
    fmt.Println("ColleagueB: Action B")
    c.mediator.CoordinateB()
}

func main() {
    // 外观模式示例
    facade := NewFacade()
    facade.Execute()

    // 中介者模式示例
    mediator := NewMediator()
    colleagueA := NewColleagueA(mediator)
    colleagueB := NewColleagueB(mediator)
    mediator.SetColleagueA(colleagueA)
    mediator.SetColleagueB(colleagueB)
    colleagueA.ActionA()
}

在示例中,外观模式通过封装子系统A和B提供了统一的接口外观对象(Facade),客户端只需与外观对象进行交互。

而中介者模式中,中介者对象(Mediator)被用来协调同事对象(ColleagueA和ColleagueB)之间的交互,同事对象不直接耦合,而是通过中介者进行通信。

总结起来,外观模式主要简化了客户端与复杂子系统之间的接口,而中介者模式是用来减少对象间直接耦合。

总结

设计模式中的外观模式旨在简化客户端与复杂子系统之间的交互,通过提供一个统一的接口或门面来隐藏子系统的复杂性。外观模式封装了子系统的一组接口,使客户端更容易使用子系统的功能。

外观对象本身在未来的扩展中需要保持稳定,如果需要扩展或修改子系统的功能,可以通过添加新的子系统、修改子系统的行为或通过继承和重写外观对象来实现。

与外观模式相比,中介者模式的主要目的是减少对象之间的直接耦合。中介者模式通过引入一个中介者对象,将对象间的通信集中到该对象中进行协调,从而降低了对象间的依赖关系。中介者模式中,对象不再直接相互引用,而是通过中介者对象来进行通信。总的来说,外观模式和中介者模式在目的和实现方式上存在区别:外观模式简化了客户端与复杂子系统之间的交互,中介者模式减少对象间的直接耦合。外观模式通过封装子系统提供统一的接口,而中介者模式通过引入中介者对象协调对象间的交互。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容