日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
程序里對象很深很大,可以用這個設計模式緩解一下

如果一個類的有非常多的屬性,層級還很深。這個妥妥的是我的對象很大,你創(chuàng)建的時候忍一下......那你每次要創(chuàng)建的時候都忍一下?有沒有一種好的方式讓我們創(chuàng)建太的時候使用體驗更好一點呢? 今天的文章里就給大家介紹一種設計模式,來解決這個問題。

成都創(chuàng)新互聯(lián)專注于紅山企業(yè)網(wǎng)站建設,成都響應式網(wǎng)站建設,成都做商城網(wǎng)站。紅山網(wǎng)站建設公司,為紅山等地區(qū)提供建站服務。全流程按需設計,專業(yè)設計,全程項目跟蹤,成都創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務

這篇內(nèi)容要說的是創(chuàng)造型設計模式里的原型模式,其實在 Java、Go之類的編程語言里其實原型模式用的并不頻繁并不太常用,如果寫過點 JS 代碼的話,大家可能聽說過原型鏈這么個東西,原型模式在 JavaScript 實現(xiàn)里確實廣泛應用,它那個面向?qū)ο蟾?Java、C++ 這些語言的面向?qū)ο蟮膶崿F(xiàn)方式還不太一樣,繼承其實是通過原型克隆出來,在拷貝出來的原型的基礎上再繼續(xù)添加或者修改來實現(xiàn)的。

什么是原型模式

通過復制、拷貝或者叫克隆已有對象的方式來創(chuàng)建新對象的設計模式叫做原型模式,被拷貝的對象也被稱作原型對象。

原型對象按照慣例,會暴露出一個 Clone 方法,給外部調(diào)用者一個機會來從自己這里“零成本”的克隆出一個新對象。

這里的“零成本”說的是,調(diào)用者啥都不用干,干等著,原型對象在 Clone 方法里自己克隆出自己,給到調(diào)用者,所以按照這個約定所有原型對象都要實現(xiàn)一個 Clone 方法。

type Prototype interface {
Clone() SpecificType
}

這里我們用UML類圖描述一下原型模式中各角色擁有的行為以及它們之間的關系

原型模式--UML類圖

至于原型對象克隆自己的時候用的是深拷貝還是淺拷貝?可以先理解成是都用深拷貝,等完全掌握這種思想后,可以再根據(jù)實際情況,比如為了節(jié)省空間、以及減少編寫克隆方法的復雜度時可以兩者綜合使用。

原型模式更多的是闡述一種編程模式,并沒有限制我們用什么方式實現(xiàn)。比如下面這個深拷貝和淺拷貝結(jié)合使用的例子。

// 示例代碼來自:https://lailin.xyz/post/prototype.html
package prototype

import (
"encoding/json"
"time"
)

// Keyword 搜索關鍵字
type Keyword struct {
word string
visit int
UpdatedAt *time.Time
}

// Clone 這里使用序列化與反序列化的方式深拷貝
func (k *Keyword) Clone() *Keyword {
var newKeyword Keyword
b, _ := json.Marshal(k)
json.Unmarshal(b, &newKeyword)
return &newKeyword
}

// Keywords 關鍵字 map
type Keywords map[string]*Keyword

// Clone 復制一個新的 keywords
// updatedWords: 需要更新的關鍵詞列表,由于從數(shù)據(jù)庫中獲取數(shù)據(jù)常常是數(shù)組的方式
func (words Keywords) Clone(updatedWords []*Keyword) Keywords {
newKeywords := Keywords{}

for k, v := range words {
// 這里是淺拷貝,直接拷貝了地址
newKeywords[k] = v
}

// 替換掉需要更新的字段,這里用的是深拷貝
for _, word := range updatedWords {
newKeywords[word.word] = word.Clone()
}

return newKeywords
}

使用原型模式的目的

使用原型模式的目的主要是為了節(jié)省創(chuàng)建對象所花費的時間和資源消耗,提升性能。

還有一點就是,比如全局配置對象這種也可以當成原型對象,如果不想讓程序在運行時修改初始化好的原型對象,導致影響其他線程的程序執(zhí)行的時候,也可以用原型模式快速拷貝出一份原型對象,再做運行時自定義修改。

使用場景

當對象的創(chuàng)建成本比較大,并且同一個類的不同對象間差別不大時(大部分屬性值相同),如果對象的屬性值需要經(jīng)過復雜的計算、排序,或者需要從網(wǎng)絡、DB等這些慢IO中獲取、亦或者或者屬性值擁有很深的層級,這時就是原型模式發(fā)揮作用的地方了。

因為對象在內(nèi)存中復制自己遠比每次創(chuàng)建對象時重走一遍上面說的操作要來高效的多。

下面再來一個例子,讓我們更好的理解原型模式的優(yōu)點。

利用原型模式實現(xiàn)文檔樹

下面是一個類似 DOM 樹對象的例子,因為 DOM 對象往往層級會很深,那么要創(chuàng)建類似的DOM樹的時候能讓我們更好的理解原型模式的優(yōu)勢。

這個示例代碼來自:https://blog.ralch.com/articles/design-patterns/golang-prototype/

package dom

import (
"bytes"
"fmt"
)

// Node a document object model node
type Node interface {
// Strings returns nodes text representation
String() string
// Parent returns the node parent
Parent() Node
// SetParent sets the node parent
SetParent(node Node)
// Children returns the node children nodes
Children() []Node
// AddChild adds a child node
AddChild(child Node)
// Clone clones a node
Clone() Node
}

// Element represents an element in document object model
type Element struct {
text string
parent Node
children []Node
}

// NewElement makes a new element
func NewElement(text string) *Element {
return &Element{
text: text,
parent: nil,
children: make([]Node, 0),
}
}

// Parent returns the element parent
func (e *Element) Parent() Node {
return e.parent
}

// SetParent sets the element parent
func (e *Element) SetParent(node Node) {
e.parent = node
}

// Children returns the element children elements
func (e *Element) Children() []Node {
return e.children
}

// AddChild adds a child element
func (e *Element) AddChild(child Node) {
copy := child.Clone()
copy.SetParent(e)
e.children = append(e.children, copy)
}

// Clone makes a copy of particular element. Note that the element becomes a
// root of new orphan tree
func (e *Element) Clone() Node {
copy := &Element{
text: e.text,
parent: nil,
children: make([]Node, 0),
}
for _, child := range e.children {
copy.AddChild(child)
}
return copy
}

// String returns string representation of element
func (e *Element) String() string {
buffer := bytes.NewBufferString(e.text)

for _, c := range e.Children() {
text := c.String()
fmt.Fprintf(buffer, "\n %s", text)
}

return buffer.String()
}

上面的DOM對象-- Node、Element 這些都支持原型模式要求的 Clone 方法,那么有了這個原型克隆的能力后,假如我們想根據(jù)創(chuàng)建好的 DOM 樹上克隆出一個子分支作為一顆獨立的 DOM 樹對象的時候,就可以像下面這樣簡單地執(zhí)行 Node.Clone() 把節(jié)點和其下面的子節(jié)點全部拷貝出去。比我們使用構造方法再重新構造樹形結(jié)構要方便許多。

下面的例子是用DOM樹結(jié)構創(chuàng)建一下公司里的職級關系,然后還可以從任意層級克隆出一顆新的樹。

func main() {
// 職級節(jié)點--總監(jiān)
directorNode := dom.NewElement("Director of Engineering")
// 職級節(jié)點--研發(fā)經(jīng)理
engManagerNode := dom.NewElement("Engineering Manager")
engManagerNode.AddChild(dom.NewElement("Lead Software Engineer"))
// 研發(fā)經(jīng)理是總監(jiān)的下級
directorNode.AddChild(engManagerNode)
directorNode.AddChild(engManagerNode)
// 辦公室經(jīng)理也是總監(jiān)的下級
officeManagerNode := dom.NewElement("Office Manager")
directorNode.AddChild(officeManagerNode)
fmt.Println("")
fmt.Println("# Company Hierarchy")
fmt.Print(directorNode)
fmt.Println("")
// 從研發(fā)經(jīng)理節(jié)點克隆出一顆新的樹
fmt.Println("# Team Hiearachy")
fmt.Print(engManagerNode.Clone())
}

原型模式總結(jié)

關于原型模式的總結(jié),我們先來說一下原型模式的優(yōu)缺點。

原型模式的優(yōu)點

  • 某些時候克隆比直接new一個對象再逐屬性賦值的過程更簡潔高效,比如創(chuàng)建層級很深的對象的時候,克隆比直接用構造會方便很多。
  • 可以使用深克隆方式保存對象的狀態(tài),可輔助實現(xiàn)撤銷操作。

原型模式的缺點

  • clone方法位于類的內(nèi)部,當對已有類進行改造的時候,需要修改代碼,違背了開閉原則。
  • 當實現(xiàn)深克隆時,需要編寫較為復雜的代碼,尤其當對象之間存在多重嵌套引用時,為了實現(xiàn)深克隆,每一層對象對應的類都必須支持深克隆。因此,深克隆、淺克隆需要運用得當。

在項目中使用原型模式時,可能需要在項目初始化時就把提供克隆能力的原型對象創(chuàng)建好,在多線程環(huán)境下,每個線程處理任務的時候,用到了相關對象,可以去原型對象那里拷貝。不過適合當作原型對象的數(shù)據(jù)并不多,所以原型模式在開發(fā)中的使用頻率并不高,如果有機會做項目架構,可以適當考慮,確實需要再在項目中引入這種設計模式。


分享標題:程序里對象很深很大,可以用這個設計模式緩解一下
地址分享:http://www.dlmjj.cn/article/dhepcie.html