关于结构体:Go语言实现的23种设计模式之结构型模式

摘要:本文次要聚焦在结构型模式(Structural Pattern)上,其次要思维是将多个对象组装成较大的构造,并同时放弃构造的灵便和高效,从程序的构造上解决模块之间的耦合问题。本文分享自华为云社区《快来,这里有23种设计模式的Go语言实现(二)》,原文作者:元闰子。 本文次要聚焦在结构型模式(Structural Pattern)上,其次要思维是将多个对象组装成较大的构造,并同时放弃构造的灵便和高效,从程序的构造上解决模块之间的耦合问题。 组合模式(Composite Pattern) 简述在面向对象编程中,有两个常见的对象设计办法,组合和继承,两者都能够解决代码复用的问题,然而应用后者时容易呈现继承档次过深,对象关系过于简单的副作用,从而导致代码的可维护性变差。因而,一个经典的面向对象设计准则是:组合优于继承。 咱们都晓得,组合所示意的语义为“has-a”,也就是局部和整体的关系,最经典的组合模式形容如下: 将对象组合成树形构造以示意“局部-整体”的层次结构,使得用户对单个对象和组合对象的应用具备一致性。 Go语言人造就反对了组合模式,而且从它不反对继承关系的特点来看,Go也奉行了组合优于继承的准则,激励大家在进行程序设计时多采纳组合的办法。Go实现组合模式的形式有两种,别离是间接组合(Direct Composition)和嵌入组合(Embedding Composition),上面咱们一起探讨这两种不同的实现办法。 Go实现间接组合(Direct Composition)的实现形式相似于Java/C++,就是将一个对象作为另一个对象的成员属性。 一个典型的实现如《应用Go实现GoF的23种设计模式(一)》中所举的例子,一个Message构造体,由Header和Body所组成。那么Message就是一个整体,而Header和Body则为音讯的组成部分。 type Message struct { Header *Header Body *Body}当初,咱们来看一个略微简单一点的例子,同样思考上一篇文章中所形容的插件架构格调的音讯解决零碎。后面咱们用形象工厂模式解决了插件加载的问题,通常,每个插件都会有一个生命周期,常见的就是启动状态和进行状态,当初咱们应用组合模式来解决插件的启动和进行问题。 首先给Plugin接口增加几个生命周期相干的办法: package plugin...// 插件运行状态type Status uint8const ( Stopped Status = iota Started)type Plugin interface { // 启动插件 Start() // 进行插件 Stop() // 返回插件以后的运行状态 Status() Status}// Input、Filter、Output三类插件接口的定义跟上一篇文章相似// 这里应用Message构造体代替了原来的string,使得语义更清晰type Input interface { Plugin Receive() *msg.Message}type Filter interface { Plugin Process(msg *msg.Message) *msg.Message}type Output interface { Plugin Send(msg *msg.Message)}对于插件化的音讯解决零碎而言,所有皆是插件,因而咱们将Pipeine也设计成一个插件,实现Plugin接口: ...

June 21, 2021 · 4 min · jiezi

C 语言之柔性数组

一 历史在c99标准出来之前。如果要在某个结构体中使用字符串变时,为了使字符串变量存储地址能与结构体整体连在一起,需要这样实现#include <stdio.h>#include <malloc.h>#include <string.h>typedef struct pen{ int len; char data;//字符串变量}pen;int main(int argc, char argv){ char str[] = “this is a string”;//需要填入的字符串 / 动态申请一个pen类型结构体变量, 它的大小为,pen类型的本身长度, 再加上str(需要填入字符串的长度),再加1, / struct pen p = (struct pen)malloc(sizeof(pen) + strlen(str) + 1); p->data= NULL; //设置p的长度为目标字符串的长度 p->len = strlen(str); / 将目标字符串拷贝到结构体对应的位置 此处为什么p+1之后指向的是pen结构体存储空间后的位置,而不是只加一呢? 因为此处的p+1偏移的是p指向类型大小的偏移量,什么意思呢?p指向的类型为pen类型的结构体, 而pen类型的结构体大小为 len(4字节)加上 data(8个字节),由于此处有内存对齐的情况, 所以实际上pen大小为 4 + 8 + 4(这个4为内存对齐的多余空间,如果再增加一个int类型的变量, pen的大小还是为16)=16字节 所以此处p+1向后偏移了16字节,通过下方地址打印可以详细看出 / strcpy((char)(p + 1), str); //int所占字节数,不同机器不同。一般64位为4字节 printf(“sizeof(int): %ld\n”, sizeof(int)); //上文已说明,16字节 printf(“sizeof(pen): %ld\n”, sizeof(pen)); //起始地址 printf(“start: %p\n\n”, (char)p); //上文已说明,偏移后的地址 printf("(p+1) : %p\n", (char)(p+1)); //偏移后,对应的字符串 printf("(char*)(p+1): %s\n\n", (char*)(p+1)); //结构体变量data的地址 printf("&(p->data): %p\n", &(p->data)); //数据,null,此处为空,故此变量已经被浪费。访问对应字符串数据需要(char *)(p+1) printf(“p->data: %s\n\n”, p->data);}二 柔性数组通过上文我们可以看到,data字段是一个被浪费的指针(8个字节)。并且我们想取到结构体下的字符串变量时需要(char *)(p+1)写这么一串东西,既不好看,也容易出错,那有没有可以直接用p->data取到字符串并且内存是连续的,而且又不浪费data字段呢, 柔性数组 就是用来干这个的。#include <stdio.h>#include <malloc.h>#include <string.h>typedef struct pen{ int len; char data[];//柔性数组}pen;int main(int argc, char **argv){ char str[] = “this is a new string”;//需要填入的字符串 struct pen p = (struct pen)malloc(sizeof(pen) + strlen(str) + 1); p->data= NULL; p->len = strlen(str); strcpy((char *)(p+1), str); printf(“pen->data: %s\n”, p->data);}C99使用不完整类型实现柔性数组成员,在C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组(flexible array)成员(也叫伸缩性数组成员),但结构中的柔性数组成员前面必须至少一个其他成员。柔性数组成员允许结构中包含一个大小可变的数组。柔性数组成员只作为一个符号地址存在,而且必须是结构体的最后一个成员,sizeof 返回的这种结构大小不包括柔性数组的内存 (此段话摘自:https://blog.csdn.net/ce123_z…) ...

February 19, 2019 · 1 min · jiezi