go

golang原型模式

介绍

原型模式是一种创建型设计模式,其主要目的是通过复制(克隆)现有对象来创建新对象,而无需使用显式的构造函数,即无需关心具体对象的构造过程,从而避免了创建对象时的耗时操作,提高了性能。

在原型模式中,原型对象是可被复制的对象,通常实现了一个Clone方法,用于复制自身并创建一个新的对象。新对象可以是完全独立的,也可以与原型对象共享部分属性。

  • 原型接口(Prototype):定义了克隆方法 Clone(),所有实现该接口的具体原型类都要实现该方法。
  • 具体原型类(Concrete Prototype):实现了原型接口,并提供了克隆方法的具体实现。

file

优点

  • 通过clone来创建对象,提高了对象的创建效率。
  • 克隆原型对象时只需要进行必要的属性赋值,而不需要再执行复杂的初始化过程。
  • 通过克隆原型对象,可以动态地生成新的对象,而无需事先确定具体的对象类。

缺点

  • 需要为每个具体原型类实现克隆方法,这增加了代码量和维护成本。
  • 如果原型对象与其他对象存在关联关系,那么克隆对象也会受到关联对象的影响。

使用场景

原型模式用于创建重复的对象。当一个类在创建时开销比较大时(比如大量数据准备,数据库连接),我们可以缓存该对象,当下一次调用时,返回该对象的克隆。

深拷贝和浅拷贝

Clone可实现深拷贝或者浅拷贝。浅拷贝是指被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。深拷贝把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

浅拷贝代码示例

package main

import "fmt"

// 定义原型接口
type ShapePrototype interface {
    Clone() ShapePrototype
    GetType() string
}

// 定义具体原型类 Rectangle
type Rectangle struct {
    Type string
}

func (r *Rectangle) Clone() ShapePrototype {
    return &Rectangle{
        Type: r.Type,
    }
}

func (r *Rectangle) GetType() string {
    return r.Type
}

// 定义具体原型类 Circle
type Circle struct {
    Type string
}

func (c *Circle) Clone() ShapePrototype {
    return &Circle{
        Type: c.Type,
    }
}

func (c *Circle) GetType() string {
    return c.Type
}

func main() {
    // 创建矩形原型对象
    rectanglePrototype := &Rectangle{
        Type: "Rectangle",
    }
    fmt.Println("Rectangle Type:", rectanglePrototype.GetType())
    // 克隆矩形原型对象来创建新对象
    rectangle := rectanglePrototype.Clone().(*Rectangle)
    fmt.Println("Rectangle Type:", rectangle.GetType())

    // 创建圆形原型对象
    circlePrototype := &Circle{
        Type: "Circle",
    }
    fmt.Println("Circle Type:", circlePrototype.GetType())
    // 克隆圆形原型对象来创建新对象
    circle := circlePrototype.Clone().(*Circle)
    fmt.Println("Circle Type:", circle.GetType())
}

file

在上述代码中,通过调用Clone()方法,可以很方便的创建新对象。Clone()方法返回了一个新的Rectangle对象,并将原对象的Type属性赋值给新对象的Type属性。这是一个浅拷贝,因为没有递归地复制其他对象。

深拷贝代码示例

如果要实现深拷贝,需要在原型对象和克隆对象之间复制引用类型的属性,并创建独立的副本。

下面是一个深拷贝的示例:

// 具体原型类 Rectangle
package main

import (
    "fmt"
)

// 原型接口
type ShapePrototypes interface {
    Clone() ShapePrototypes
}

// 具体原型类 - 矩形
type RectAngle struct {
    Type string
    Data []int // 引用类型属性
}

func (r *RectAngle) Clone() ShapePrototypes {
    // 创建新对象
    clone := &RectAngle{
        Type: r.Type,
    }

    // 复制引用类型属性
    clone.Data = make([]int, len(r.Data))
    copy(clone.Data, r.Data)

    return clone
}

func main() {
    // 创建原型对象
    rectanglePrototype := &RectAngle{
        Type: "Rectangle",
        Data: []int{1, 2, 3},
    }

    // 克隆原型对象来创建新对象
    rectangle := rectanglePrototype.Clone().(*RectAngle)

    // 修改克隆对象的属性
    rectangle.Data[0] = 100

    // 打印原型对象和克隆对象的属性
    fmt.Println(rectanglePrototype.Data) // [1 2 3]
    fmt.Println(rectangle.Data)          // [100 2 3]
    fmt.Println(rectanglePrototype.Data) // [1 2 3]
}

可以看到,克隆对象的Data属性修改后,并不影响到原型对象的Data属性,因为这是独立的副本。这证明了深拷贝的实现。

分类: go
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
内联反馈
查看所有评论

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x