golang 디자인 모델 - kubernetes 소스 코드 를 예 로 들 면
design pattern 소개 디자인 모델 engineer pattern 정리 선진 적 인 공정 모델
design pattern
레 퍼 런 스
simplefactory
golang 에 게 는 Newxx 함수 입 니 다. interface 로 돌아 갑 니 다. kubernetes interface 는 어디서나 볼 수 있 습 니 다. interface 로 추상 적 인 것 은 interface 라 고 할 수 있 습 니 다. 예 를 들 어 보 세 요.
// k8s.io/kubernetes/vendor/k8s.io/client-go/tools/cache/store.go
func NewStore(keyFunc KeyFunc) Store {
return &cache{
cacheStorage: NewThreadSafeStore(Indexers{}, Indices{}),
keyFunc: keyFunc,
}
}
type cache struct {
// cacheStorage bears the burden of thread safety for the cache
cacheStorage ThreadSafeStore
// keyFunc is used to make the key for objects stored in and retrieved from items, and
// should be deterministic.
keyFunc KeyFunc
}
type Store interface {
Add(obj interface{}) error
Update(obj interface{}) error
Delete(obj interface{}) error
List() []interface{}
ListKeys() []string
Get(obj interface{}) (item interface{}, exists bool, err error)
GetByKey(key string) (item interface{}, exists bool, err error)
// Replace will delete the contents of the store, using instead the
// given list. Store takes ownership of the list, you should not reference
// it after calling this function.
Replace([]interface{}, string) error
Resync() error
}
facade / adapter / decorator / delegate / bridge / mediator / composite
조합 모델 의 서로 다른 형식 은 곳곳에서 볼 수 있 고 그 중의 차 이 를 깊이 연구 할 필요 도 없다.
singleton
kubernetes / golang 은 거의 사용 하지 않 습 니 다. 일반적으로 전역 변수 (예 를 들 어 설정) (예 를 들 어 net / http package 의 http. DefaultClient 와 http. Default ServeMux) 를 사용 하거나 context 로 전 달 됩 니 다.실현 방식 은 marcio. io / 2015 / 07 / sin 을 참고 할 수 있 습 니 다.
흔히 볼 수 있 는 방법 중 하 나 는 double check 입 니 다.
func GetInstance() *singleton {
if instance == nil { // 's not fully atomic
mu.Lock()
defer mu.Unlock()
if instance == nil {
instance = &singleton{}
}
}
return instance
}
하지만 골 랑 에 서 는 더 좋 은 방법 이 있 습 니 다. "Once" 를 사용 하 세 요.
type singleton struct {
}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
factory/ abstract factory / builder
이 몇 가지 creational patterns 에 대한 차이 점:
factory
// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/runtime/serializer/codec_factory.go
func NewCodecFactory(scheme *runtime.Scheme) CodecFactory {
serializers := newSerializersForScheme(scheme, json.DefaultMetaFactory)
return newCodecFactory(scheme, serializers)
}
func (f CodecFactory) LegacyCodec(version ...schema.GroupVersion) runtime.Codec {
return versioning.NewDefaultingCodecForScheme(f.scheme, f.legacySerializer, f.universal, schema.GroupVersions(version), runtime.InternalGroupVersioner)
}
abstract factory 는 Shared InformerFactory 를 예 로 들 면 이 factory 는 app / core / batch... 등 각종 인 터 페 이 스 를 만 들 수 있 습 니 다.
//k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion/factory.go
func NewSharedInformerFactory(client internalclientset.Interface, defaultResync time.Duration) SharedInformerFactory {
return &sharedInformerFactory{
client: client,
defaultResync: defaultResync,
informers: make(map[reflect.Type]cache.SharedIndexInformer),
startedInformers: make(map[reflect.Type]bool),
}
}
// SharedInformerFactory provides shared informers for resources in all known
// API group versions.
type SharedInformerFactory interface {
internalinterfaces.SharedInformerFactory
ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
WaitForCacheSync(stopCh return apps.New(f)
}
builder
// k8s.io/kubernetes/pkg/controller/client_builder.go
func NewForConfigOrDie(c *rest.Config) *Clientset {
var cs Clientset
cs.admissionregistrationV1alpha1 = admissionregistrationv1alpha1.NewForConfigOrDie(c)
cs.appsV1beta1 = appsv1beta1.NewForConfigOrDie(c)
cs.appsV1beta2 = appsv1beta2.NewForConfigOrDie(c)
cs.appsV1 = appsv1.NewForConfigOrDie(c)
cs.authenticationV1 = authenticationv1.NewForConfigOrDie(c)
cs.authenticationV1beta1 = authenticationv1beta1.NewForConfigOrDie(c)
cs.authorizationV1 = authorizationv1.NewForConfigOrDie(c)
cs.authorizationV1beta1 = authorizationv1beta1.NewForConfigOrDie(c)
cs.autoscalingV1 = autoscalingv1.NewForConfigOrDie(c)
cs.autoscalingV2beta1 = autoscalingv2beta1.NewForConfigOrDie(c)
cs.batchV1 = batchv1.NewForConfigOrDie(c)
cs.batchV1beta1 = batchv1beta1.NewForConfigOrDie(c)
cs.batchV2alpha1 = batchv2alpha1.NewForConfigOrDie(c)
cs.certificatesV1beta1 = certificatesv1beta1.NewForConfigOrDie(c)
cs.coreV1 = corev1.NewForConfigOrDie(c)
cs.extensionsV1beta1 = extensionsv1beta1.NewForConfigOrDie(c)
cs.networkingV1 = networkingv1.NewForConfigOrDie(c)
cs.policyV1beta1 = policyv1beta1.NewForConfigOrDie(c)
cs.rbacV1 = rbacv1.NewForConfigOrDie(c)
cs.rbacV1beta1 = rbacv1beta1.NewForConfigOrDie(c)
cs.rbacV1alpha1 = rbacv1alpha1.NewForConfigOrDie(c)
cs.schedulingV1alpha1 = schedulingv1alpha1.NewForConfigOrDie(c)
cs.settingsV1alpha1 = settingsv1alpha1.NewForConfigOrDie(c)
cs.storageV1beta1 = storagev1beta1.NewForConfigOrDie(c)
cs.storageV1 = storagev1.NewForConfigOrDie(c)
cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c)
return &cs
}
prototype
프로 토 타 입 모드 는 생 성 모드 의 하나 로 '복사' 를 통 해 이미 존재 하 는 인 스 턴 스 를 통 해 새로운 인 스 턴 스 를 되 돌려 주 는 것 이 특징 입 니 다.복 제 된 인 스 턴 스 는 바로 우리 가 말 하 는 '원형' 이 고 이 원형 은 맞 춤 형 이다.The Prototype Pattern creates duplicate objects while keeping
performance
in mind. It's a part of the creational patterns and provides one of the best ways to create an object. blog. ralch. com / tutorial / de 참조...
kubernetes 는 deepcopy - gen 자동 생 성 대상 의 deepcopy 등 방법 을 사 용 했 습 니 다. 예 를 들 어 아래 생 성 된 예 입 니 다.
// k8s.io/kubernetes/vendor/k8s.io/apiserver/pkg/apis/audit/zz_generated.deepcopy.go
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GroupResources) DeepCopyInto(out *GroupResources) {
*out = *in
if in.Resources != nil {
in, out := &in.Resources, &out.Resources
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.ResourceNames != nil {
in, out := &in.ResourceNames, &out.ResourceNames
*out = make([]string, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupResources.
func (in *GroupResources) DeepCopy() *GroupResources {
if in == nil {
return nil
}
out := new(GroupResources)
in.DeepCopyInto(out)
return out
}
생 성 된 도 구 는 여기 k8s. io / kubernetes / vendor / k8s. io / code - generator / cmd / deepcopy - gen / main. go 에서 github. com / kubernetes /...
observer
이 모델 은 kubernetes 에서 도 흔히 볼 수 있다. 예 를 들 어 shared Informer 는 관찰자 모델 의 실현 이다.
// k8s.io/client-go/tools/cache/shared_informer.go
func (s *sharedIndexInformer) AddEventHandlerWithResyncPeriod(handler ResourceEventHandler, resyncPeriod time.Duration) {
...
s.processor.addListener(listener)
...
}
//
func (p *sharedProcessor) distribute(obj interface{}, sync bool) {
p.listenersLock.RLock()
defer p.listenersLock.RUnlock()
if sync {
for _, listener := range p.syncingListeners {
listener.add(obj)
}
} else {
for _, listener := range p.listeners {
listener.add(obj)
}
}
}
command
정의: 명령 모드 (Command Pattern): 하나의 요청 을 대상 으로 밀봉 하여 서로 다른 요청 으로 고객 을 매개 변수 화 할 수 있 도록 합 니 다.요청 대기 열 이나 요청 로 그 를 기록 하고 취소 가능 한 동작 을 지원 합 니 다.명령 모드 는 동작 (Action) 모드 나 트 랜 잭 션 (Transaction) 모드 라 는 별명 을 가 진 대상 행동 형 모드 입 니 다.kubernetes 의 command 는 github. com / spf 13 / cobra 를 바탕 으로 명령 을 대상 으로 만 들 었 습 니 다. 예 를 들 어 cmdRollOut 은 undo 도 실현 하 였 습 니 다.
interator
데이터 구조 와 관련 된 package 에 많이 사 용 됩 니 다. 예 를 들 어 인 용 된 라 이브 러 리 jsoniter, btree, govaidator.
// golang "go/token" Iterate , vistor ...
func (s *FileSet) Iterate(f func(*File) bool)
strategy
일련의 알고리즘 을 정의 하여 이 알고리즘 들 이 실 행 될 때 교환 할 수 있 도록 분리 알고리즘 을 개폐 원칙 에 부합 하도록 합 니 다.대상 은 어떤 행위 가 있 지만 서로 다른 장면 에서 이 행 위 는 서로 다른 실현 알고리즘 이 있다.실제로 interface 를 사용 하 는 것 은 모두 strategy 모델 과 같다. 이런 측면 에서 볼 때 strategy 모델 은 말 그대로 의 강조 의미 일 뿐 실현 에 있어 interface 가 실현 하 는 factory 모델 은 강조 하 는 점 만 다 를 뿐이다. 하 나 는 창설 형 을 강조 하 는 것 이 고 하 나 는 행위 형 예 를 강조 하 는 것 이다.
// k8s strategy, update,delete,get
// /k8s.io/kubernetes/pkg/registry/core/configmap/strategy.go
// strategy implements behavior for ConfigMap objects
type strategy struct {
runtime.ObjectTyper
names.NameGenerator
}
// Strategy is the default logic that applies when creating and updating ConfigMap
// objects via the REST API.
var Strategy = strategy{api.Scheme, names.SimpleNameGenerator}
// Strategy should implement rest.RESTCreateStrategy
var _ rest.RESTCreateStrategy = Strategy
// Strategy should implement rest.RESTUpdateStrategy
var _ rest.RESTUpdateStrategy = Strategy
func (strategy) NamespaceScoped() bool {
return true
}
func (strategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Object) {
_ = obj.(*api.ConfigMap)
}
func (strategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList {
cfg := obj.(*api.ConfigMap)
return validation.ValidateConfigMap(cfg)
}
// Canonicalize normalizes the object after validation.
func (strategy) Canonicalize(obj runtime.Object) {
}
func (strategy) AllowCreateOnUpdate() bool {
return false
}
func (strategy) PrepareForUpdate(ctx genericapirequest.Context, newObj, oldObj runtime.Object) {
_ = oldObj.(*api.ConfigMap)
_ = newObj.(*api.ConfigMap)
}
func (strategy) AllowUnconditionalUpdate() bool {
return true
}
func (strategy) ValidateUpdate(ctx genericapirequest.Context, newObj, oldObj runtime.Object) field.ErrorList {
oldCfg, newCfg := oldObj.(*api.ConfigMap), newObj.(*api.ConfigMap)
return validation.ValidateConfigMapUpdate(newCfg, oldCfg)
}
// k8s.io/kubernetes/pkg/registry/core/configmap/storage/storage.go
// NewREST returns a RESTStorage object that will work with ConfigMap objects.
func NewREST(optsGetter generic.RESTOptionsGetter) *REST {
store := &genericregistry.Store{
NewFunc: func() runtime.Object { return &api.ConfigMap{} },
NewListFunc: func() runtime.Object { return &api.ConfigMapList{} },
DefaultQualifiedResource: api.Resource("configmaps"),
CreateStrategy: configmap.Strategy,
UpdateStrategy: configmap.Strategy,
DeleteStrategy: configmap.Strategy,
}
options := &generic.StoreOptions{RESTOptions: optsGetter}
if err := store.CompleteWithOptions(options); err != nil {
panic(err) // TODO: Propagate error up
}
return &REST{store}
}
state
상태 모드 (State Pattern): 한 대상 이 내부 상태 가 바 뀔 때 행동 을 바 꿀 수 있 도록 합 니 다. 대상 이 종 류 를 수정 한 것 같 습 니 다.그 별명 은 상태 대상 (Objects for States) 이 고 상태 모델 은 대상 행위 형 모델 이다.상태 와 행 위 를 분리 하 는 것, 예 를 들 어 하나의 상태 기기 의 실현 은 바로 표준 state 모델 이다.
// k8s.io/kubernetes/vendor/github.com/coreos/etcd/raft/node.go
// Node represents a node in a raft cluster.
type Node interface {
....
Step(ctx context.Context, msg pb.Message) error
....
// Status returns the current status of the raft state machine.
Status() Status
....
}
memento
패 키 징 성 을 파괴 하지 않 는 전제 에서 대상 의 내부 상 태 를 포착 하고 이 대상 외 에 이 상 태 를 저장 합 니 다.이렇게 하면 이 대상 을 원래 저 장 된 상태 로 복원 할 수 있다.
// k8s.io/kubernetes/pkg/registry/core/service/portallocator/allocator.go
// NewFromSnapshot allocates a PortAllocator and initializes it from a snapshot.
func NewFromSnapshot(snap *api.RangeAllocation) (*PortAllocator, error) {
pr, err := net.ParsePortRange(snap.Range)
if err != nil {
return nil, err
}
r := NewPortAllocator(*pr)
if err := r.Restore(*pr, snap.Data); err != nil {
return nil, err
}
return r, nil
}
func (r *PortAllocator) Snapshot(dst *api.RangeAllocation) error {
snapshottable, ok := r.alloc.(allocator.Snapshottable)
if !ok {
return fmt.Errorf("not a snapshottable allocator")
}
rangeString, data := snapshottable.Snapshot()
dst.Range = rangeString
dst.Data = data
return nil
}
넓 은 의미 에서 볼 때 deployment, statefulset 등 대상 은 rollback 방법 을 실 현 했 고 memeto 와 유사 하 다. 예 를 들 어 deployment 는 각종 version 의 replicasset 의 history 백업 을 가지 고 역사 버 전 을 복원 하 는 데 사용 된다.k8s. io / kubernetes / pkg / controller / deployment /
flyweight / object pool
flyweight 는 대상 재 활용 을 강조 하 며 object pool 의 목적 과 같다.One difference in that flyweights are comonly immutable instances, while resources acquired from the pool usually are mutable. object pool 은 golang 과 kubernetes 에서 많이 사용 합 니 다. 예 를 들 어 공식 적 으로 sync. pool 이 있 습 니 다.
// k8s.io/kubernetes/staging/src/k8s.io/apiserver/pkg/storage/cacher.go
var timerPool sync.Pool
func (c *cacheWatcher) add(event *watchCacheEvent, budget *timeBudget) {
...
t, ok := timerPool.Get().(*time.Timer)
if ok {
t.Reset(timeout)
} else {
t = time.NewTimer(timeout)
}
defer timerPool.Put(t)
....
}
iterpreter
해석 기 모드 는 언어 문법 을 정의 하고 이 언어 해석 기 를 설계 하여 사용자 가 특정한 문법 으로 해석 기 행 위 를 제어 할 수 있 도록 한다.이것 은 kubernetes 의 각종 코드 / 문서 생 성 도구 에 많이 사 용 됩 니 다.
chain_of_responsibility
일종 의 조합 모드 입 니 다. 사용 하 는 곳 이 많 습 니 다.직책 체인 모델 은 서로 다른 직책 을 분리 하고 동태 적 으로 관련 직책 을 조합 하 는 데 사용 된다.체인 대상 은 현재 직책 대상 과 다음 직책 체인 을 포함한다.
// wrapper childrens
// k8s.io/test-infra/velodrome/transform/plugins/multiplexer_wrapper.go
func NewMultiplexerPluginWrapper(plugins ...Plugin) *MultiplexerPluginWrapper {
return &MultiplexerPluginWrapper{
plugins: plugins,
}
}
// warpper clildrens
// k8s.io/test-infra/velodrome/transform/plugins/author_logger_wrapper.go
func NewAuthorLoggerPluginWrapper(plugin Plugin) *AuthorLoggerPluginWrapper {
return &AuthorLoggerPluginWrapper{
plugin: plugin,
}
}
// , clildrens
...
visit
대상 이 방문 자 인터페이스 (예 를 들 어 Accept) 를 미리 남 겨 두 면 후기 에 대상 에 기능 을 추가 할 때 대상 을 바 꿀 필요 가 없다.본질은 외부 에서 자신의 대상 을 방문 하 는 방법 을 정의 할 수 있 도록 하 는 것 이다. 이런 측면 에서 볼 때 visit 가 하나의 함수 로 전달 되면 visit 모델 이다.즉시
func(a *A)Visit(Vistor func(*A) error){
Vistor(a)
}
예시
// k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/openapi.go
type SchemaVisitor interface {
VisitArray(*Array)
VisitMap(*Map)
VisitPrimitive(*Primitive)
VisitKind(*Kind)
VisitReference(Reference)
}
// Schema is the base definition of an openapi type.
type Schema interface {
// Giving a visitor here will let you visit the actual type.
Accept(SchemaVisitor)
// Pretty print the name of the type.
GetName() string
// Describes how to access this field.
GetPath() *Path
// Describes the field.
GetDescription() string
// Returns type extensions.
GetExtensions() map[string]interface{}
}
// /k8s.io/kubernetes/pkg/kubectl/resource/builder.go
func (b *Builder) visitByName() *Result {
...
visitors := []Visitor{}
for _, name := range b.names {
info := NewInfo(client, mapping, selectorNamespace, name, b.export)
visitors = append(visitors, info)
}
result.visitor = VisitorList(visitors)
result.sources = visitors
return result
}
engineering patterns
code generator
다음으로 전송:https://juejin.im/post/5a113e686fb9a0452936596c
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.