工厂模式

定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

  • 主要解决:主要解决接口选择的问题。
  • 何时使用:我们明确地计划不同条件下创建不同实例时。
  • 使用场景:
    • 日志记录器
    • 数据库访问
    • 设计一个连接服务器的框架

      一个函数可以自行选择用什么类来实现一个或一套方法

  1. package Factory
  2. import (
  3. "fmt"
  4. "testing"
  5. )
  6. type Restaurant interface {
  7. GetFood()
  8. }
  9. type Donglaishun struct {}
  10. func (d *Donglaishun) GetFood() {
  11. fmt.Println("东来顺")
  12. }
  13. type Qingfeng struct {}
  14. func (q *Qingfeng) GetFood() {
  15. fmt.Println("庆丰")
  16. }
  17. func NewRestaurant(name string) Restaurant{
  18. switch name {
  19. case "d":
  20. return &Donglaishun{}
  21. case "q":
  22. return &Qingfeng{}
  23. }
  24. return nil
  25. }
  26. func TestNewRestaurant(t *testing.T) {
  27. NewRestaurant(d).GetFood()
  28. NewRestaurant(d).GetFood()
  29. }

抽象工厂模式

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

  • 主要解决:主要结局接口选择的问题
  • 何时使用:系统的产品有多于一个的产品族,而系统只消费其中的某一族产品
  • 使用场景:
    • qq换皮肤,一整套一起换
    • 生成不同操作系统的程序

      一个类通过不同的方法返回不同的类

  1. package Abstract_Factory
  2. import (
  3. "fmt"
  4. "testing"
  5. )
  6. type Lunch interface{
  7. Cook()
  8. }
  9. type Rise struct {}
  10. func (r *Rise) Cook() {
  11. fmt.Println("rice")
  12. }
  13. type Tomato struct {}
  14. func (t *Tomato) Cook() {
  15. fmt.Println("tomato")
  16. }
  17. type LunchFactory interface {
  18. CreateFood() Lunch
  19. CreateVegetable() Lunch
  20. }
  21. type SimpleLunchFactory struct {}
  22. func NewSimpleLunchFactory() LunchFactory{
  23. return &SimpleLunchFactory{}
  24. }
  25. func (s *SimpleLunchFactory) CreateFood() Lunch {
  26. return &Rise{}
  27. }
  28. func (s *SimpleLunchFactory) CreateVegetable() Lunch {
  29. return &Tomato{}
  30. }
  31. func TestNewSimpleLunchFactory(t *testing.T) {
  32. factory := NewSimpleLunchFactory()
  33. food := factory.CreateFood()
  34. food.Cook()
  35. vegetable := factory.CreateVegetable()
  36. vegetable.Cook()
  37. }

外观模式

为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

  • 主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。
  • 何时使用:
    • 客户端不需要知道系统内部的复杂联系,整个系统只需提供一个”接待员”即可。
    • 定义系统的入口。
  • 使用场景:
    • 为复杂的模块或子系统提供外界访问的模块
    • 子系统相对独立
    • 预防低水平人员带来的风险

      通过返回一个简单的接口而实现了复杂的操作

  1. package Facade
  2. import (
  3. "fmt"
  4. "testing"
  5. )
  6. type CarModel struct {}
  7. func NewCarModel() *CarModel {
  8. return &CarModel{}
  9. }
  10. func (c *CarModel) SetModel() {
  11. fmt.Fprintf(outputWriter, " CarModel - SetModel\n")
  12. }
  13. type CarEngine struct {}
  14. func NewCarEngine() *CarEngine {
  15. return &CarEngine{}
  16. }
  17. func (c *CarEngine) SetEngine() {
  18. fmt.Fprintf(outputWriter, " CarEngine - SetEngine\n")
  19. }
  20. type CarBody struct {}
  21. func NewCarBody() *CarBody {
  22. return &CarBody{}
  23. }
  24. func (c *CarBody) SetBody() {
  25. fmt.Fprintf(outputWriter, " CarBody - SetBody\n")
  26. }
  27. type CarAccessories struct {}
  28. func NewCarAccessories() *CarAccessories {
  29. return &CarAccessories{}
  30. }
  31. func (c *CarAccessories) SetAccessories() {
  32. fmt.Fprintf(outputWriter, " CarAccessories - SetAccessories\n")
  33. }
  34. type CarFacade struct {
  35. accessories *CarAccessories
  36. body *CarBody
  37. engine *CarEngine
  38. model *CarModel
  39. }
  40. func NewCarFacade() *CarFacade {
  41. return &CarFacade{
  42. accessories: NewCarAccessories(),
  43. body: NewCarBody(),
  44. engine: NewCarEngine(),
  45. model: NewCarModel(),
  46. }
  47. }
  48. func (c *CarFacade) CreateCompleteCar() {
  49. fmt.Fprintf(outputWriter, "******** Creating a Car **********\n")
  50. c.model.SetModel()
  51. c.engine.SetEngine()
  52. c.body.SetBody()
  53. c.accessories.SetAccessories()
  54. fmt.Fprintf(outputWriter, "******** Car creation is completed. **********\n")
  55. }
  56. func TestCarFacade_CreateCompleteCar(t *testing.T) {
  57. facade := NewCarFacade()
  58. facade.CreateCompleteCar()
  59. }

建造者模式

将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

  • 主要解决:主要解决在软件系统中,有时候面临着”一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
  • 何时使用:一些基本部件不会变,而其组合经常变化的时候
  • 场景:
    • 套餐,东西不变,但组合一直变

      一些基本部件不会变,而组合经常变化

  1. package Builder
  2. import (
  3. "fmt"
  4. "testing"
  5. )
  6. type Builder interface {
  7. Build()
  8. }
  9. type Director struct {
  10. builder Builder
  11. }
  12. func NewDirector(b Builder) Director {
  13. return Director{builder: b}
  14. }
  15. func (d *Director) Construct() {
  16. d.builder.Build()
  17. }
  18. type ConcreteBuilder struct {
  19. built bool
  20. }
  21. func NewConcreteBuilder() ConcreteBuilder {
  22. return ConcreteBuilder{false}
  23. }
  24. func (b *ConcreteBuilder) Build() {
  25. b.built = true
  26. }
  27. type Product struct {
  28. Built bool
  29. }
  30. func (b *ConcreteBuilder) GetResult() Product {
  31. return Product{b.built}
  32. }
  33. func TestConcreteBuilder_GetResult(t *testing.T) {
  34. builder := NewConcreteBuilder()
  35. director := NewDirector(&builder)
  36. director.Construct()
  37. product := builder.GetResult()
  38. fmt.Println(product.Built)
  39. }

桥接模式

将抽象部分与实现部分分离,使它们都可以独立的变化。

  • 主要解决:在有很多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不方便
  • 何时使用:实现系统可能有多个角度分类,每一种角度都可能变化
  • 场景:
    • 系统需要在构建的抽象化角色于具体化角色之间增加更多灵活性(模型-实例)
    • 不希望使用继承或因为多层次导致系统类的个数急剧增加的系统
    • 一个类存在两个独立变化的维度,且两个维度都需要扩展

      具体的描述某些维度

  1. package Bridage
  2. import (
  3. "fmt"
  4. "time"
  5. "testing"
  6. )
  7. type Draw interface {
  8. DrawCircle(radius, x, y int)
  9. }
  10. type RedCircle struct {}
  11. func (g *RedCircle) DrawCircle(radius, x, y int) {
  12. fmt.Println("radius、x、y:", radius, x, y)
  13. }
  14. type YellowCircle struct {}
  15. func (g *YellowCircle) DrawCircle(radius, x, y int) {
  16. fmt.Println("radius、x、y:", radius, x, y)
  17. }
  18. type Shape struct {
  19. draw Draw
  20. }
  21. func (s *Shape) Shape(d Draw) {
  22. s.draw = d
  23. time.Now().Unix()
  24. }
  25. type Circle struct {
  26. shape Shape
  27. x int
  28. y int
  29. radius int
  30. }
  31. func (c *Circle) Constructor(x int, y int, radius int, draw Draw) {
  32. c.x = x
  33. c.y = y
  34. c.radius = radius
  35. c.shape.Shape(draw)
  36. }
  37. func (c *Circle) Cook() {
  38. c.shape.draw.DrawCircle(c.radius, c.x, c.y)
  39. }
  40. func TestCircle_Draw(t *testing.T) {
  41. redCircle := Circle{}
  42. redCircle.Constructor(100, 100, 10, &RedCircle{})
  43. yellowCircle := Circle{}
  44. yellowCircle.Constructor(200, 200, 20, &YellowCircle{})
  45. redCircle.Cook()
  46. yellowCircle.Cook()
  47. }

命令模式

将一个请求封装成一个对象,从而可以用不同的请求对客户进行参数化。

  • 主要解决:某些场合下,紧耦合的设计无法满足行为
  • 何时使用:在某些场合,比如要对行为进行”记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将”行为请求者”与”行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
  • 使用场景:
    • GUI的每一个按钮
    • 模拟CMD

      使用一个函数可以灵活的使用其方法

  1. package Command
  2. import (
  3. "fmt"
  4. "testing"
  5. )
  6. type Person struct {
  7. name string
  8. cmd Command
  9. }
  10. type Command struct {
  11. person *Person
  12. method func()
  13. }
  14. func NewCommand(p *Person, method func()) Command {
  15. return Command{
  16. person: p,
  17. method: method,
  18. }
  19. }
  20. func (c *Command) Execute() {
  21. c.method()
  22. }
  23. func NewPerson(name string, cmd Command) Person {
  24. return Person{
  25. name: name,
  26. cmd: cmd,
  27. }
  28. }
  29. func (p *Person) Buy() {
  30. fmt.Println(fmt.Sprintf("%s is buying ", p.name))
  31. p.cmd.Execute()
  32. }
  33. func (p *Person) Cook() {
  34. fmt.Println(fmt.Sprintf("%s is cooking ", p.name))
  35. p.cmd.Execute()
  36. }
  37. func (p *Person) Wash() {
  38. fmt.Println(fmt.Sprintf("%s is washing ", p.name))
  39. p.cmd.Execute()
  40. }
  41. func (p *Person) Listen() {
  42. fmt.Println(fmt.Sprintf("%s is Listening ", p.name))
  43. }
  44. func (p *Person) Talk() {
  45. fmt.Println(fmt.Sprintf("%s is Talking ", p.name))
  46. p.cmd.Execute()
  47. }
  48. func TestCommand_Execute(t *testing.T) {
  49. laowang := NewPerson("wang", NewCommand(nil, nil))
  50. laozhang := NewPerson("zhang", NewCommand(&laowang, laowang.Listen))
  51. laofeng := NewPerson("feng", NewCommand(&laozhang, laozhang.Buy))
  52. laoding := NewPerson("ding", NewCommand(&laofeng, loafeng.Cook))
  53. laoli := NewPerson("li", NewCommand(&laoding, laoding.Wash))
  54. laoli.Talk()
  55. }