d作者d语言中组件式编程
D编程语言中组件编程
作者:沃尔特.布莱特(Walter Bright)
我们一直在尝试编写可重用
软件.作者
35年的编程经验,但可重用的很少.复制/粘贴
不算,我在某处可能
错过了,其他程序员也经常有同样感觉.不是缺少实践
,也不是现在比过去强
,应该有深入
理解.
有问题的样儿:抽象有漏洞,依赖其他代码,组件太具体(对A适用,但对B不适用)
,要回到问题:
什么是组件?
● 不仅仅是可重用
软件,有很多非真正
组件的可重用代码库.
● 组件有预定义
接口.这样,即使单独
开发的,也可交换,添加和组合
他们.
● 多数库暴露
接口,但连接至其他库,要求助手
.
那么,
什么是通用组件接口?
● 读
输入
● 处理
输入
● 写
输出
即使程序不是,但子系统
适用该模型
,伪码表示:
源 => 算法 => 汇
或这样:
源 => 1算法 => 2算法 => 汇
在联操的文件和过滤
命令行模型
上见过.
● 非常
成功和强大
● 按"文件接口"的对接
C
● 文件既是源又是汇
● 算法是"过滤器"
● 管道连接它们
● 甚至还有伪文件
系统优势
缺点
● 进化
而非设计
● 按字节流
对待数据
● 对随机访问
算法,不适用
● 但它显示了组件是什么
,及分发
.
看我代码
void main(string[] args)
{
string pattern = args[1];
while (!feof(stdin))
{
string line = getLine(stdin);
if (match(pattern, line))
writeLine(stdout, line);
}
}
它不像源 => 算法 =>汇
.进入旋涡
而非组装厂
.这样更好:
void main(string[] args)
{
string pattern = args[1];
stdin => byLines => match(pattern) => stdout; //输入,按行,匹配,输出
}
下一个设计
● C++
面向对象,未导致更好组件
编程
● C++ iostreams
,通过重载>>
运算符,开始看起来像源 => 算法 =>汇
,但仍然是读/写
文件.
● 许多成功的C++
库,但它们不是这里讨论的组件
.
● 革命性的C++
迭代器和算法,STL
标准模板库:不仅仅是文件,算法,通用接口,编译成高效代码
:
for (i = L.begin(); i != L.end(); ++i)
... 用(*i)干活 ...
仍像循环,然后有std::for_each(),std::transform()
,但不能组合,因为迭代器
要成对出现.
回到绘图板
● 源:流,容器,生成器
● 算法:过滤,映射,缩减,排序
● 汇:流,容器
源 | 算法 | 汇 |
---|---|---|
file | sort | file |
tree | filter | tree |
array | map | array |
socket | reduce | socket |
list | max | list |
iota | search | |
随机数 | 奇数,数单词 |
总结要求
● 可组合性
● 支持强大封装
● 生成工业品质高效代码
● 自然语法:源=>算法=>汇
● 可同未知类型
一起用
输入区间
要求
● 是否有可用数据?bool
为空;
● 读当前
输入数据:E front;
.
● 步进至下一数据:void popFront();
.
输入区间
非类型
● 它是概念
.
● 需要3个
原语:empty,front,popFront
从stdin
读符:
private import core.stdc.stdio;
struct StdinByChar {//三个原语
@property bool empty() {
if (hasChar)
return false;
auto c = fgetc(stdin);
if (c == EOF)
return true;
ch = cast(char)c;
hasChar = true;
return false;
}
@property char front() { return ch; }
void popFront() { hasChar = false; }
private:
char ch;
bool hasChar;
}
从stdin
读,写至stdout
:
for (auto r = StdinByChar();
!r.empty;
r.popFront())
{//注意原语.
auto c = r.front; //这里
fputc(c, stdout);
}
加点语言神奇
:
foreach (c; StdinByChar())
fputc(c, stdout);
//注意,这里无类型
前向区间
加了个保存
属性:
@property R save;
(R为前向区间类型)
返回位置副本
,而非数据.原与副本
都可独立遍历区间.单链表
是典型例子.归并排序
用前向区间
.
双向区间
加了个属性与方法
:
@property E back;
void popBack();
类似front和popFront
,但反向工作.双链表
是典型,UTF-8和UTF-16
也是双向
编码.
随机访问区间
加上:
E opIndex(size_t I);
用[]
来索引数据,并加了2个
选项:
1,BidirectionalRange(双向区间)
的@property size_t length;
长度属性,可为无穷
.
2,无穷的ForwardRange(前向区间)
.对无穷
区间,空的
总为假
.
汇(输出区间)
有个(put)放
方法:
void put(E e);
放E
类型的e
进区间
.
输出区间写入标准输出
struct StdoutByChar {
void put(char c) {
if (fputc(c, stdout) == EOF)
throw new Exception("标出错误");
}
}
回忆早先:
foreach (c; StdinByChar())
fputc(c, stdout);
用输出区间
,变成:
StdoutByChar r;
foreach (c; StdinByChar())
r.put(c);
甚至可正确
处理错误!它从输入复制
到输出.复制:
void copy(ref StdinByChar source,
ref StdoutByChar sink) {
foreach (c; source)
sink.put(c);
}
只要有StdinByChar
和StdoutByChar
类型,可复制/粘贴
至其他类型:
用模板
void copy(Source, Sink)(ref Source source,
ref Sink sink) {
foreach (c; source)
sink.put(c);
}
解决了通用
问题,但接受任意输入类型
,而导致灾难,加上约束:
Sink copy(Source, Sink)(ref Source source,
ref Sink sink
if (isInputRange!Source &&
isOutputRange!(Sink, ElementType!Source
{
foreach (c; source)
sink.put(c);
return sink;
}
这是我们第一个算法!(返回
是为了可组合.)
当前状态
StdinByChar source;
StdoutByChar sink;
copy(source, sink);
加上统调(UFCS)
:func(a,b,c)
,可写成:a.func(b,c)
,现在这样:
StdinByChar source;
StdoutByChar sink;
source.copy(sink);
过滤:
int[] arr = [1,2,3,4,5];
auto r = arr.filter!(a => a < 3);
writeln(r);
输出:
[1, 2]
映射:
int[] arr = [1,2,3,4,5];
auto r = arr.map!(a => a * a);
writeln(r);
输出:
[1, 4, 9, 16, 25]
化简:
int[] arr = [1,2,3,4,5];
auto r = arr.reduce!((a,b) => a + b);
writeln(r);
输出:
15
连在一起:
import std.stdio;
import std.array;
import std.algorithm;
void main() {
stdin.byLine(KeepTerminator.yes)
map!(a => a.idup).
array.
sort.
copy(stdout.lockingTextWriter());
}
还需要特征:
● 处理错误的异常
● 模板函数
● 模板约束
● UFCS(统调)
● 区间
是概念,而不是类型
● 内联,自定义,优化
● 限定
● 推导
类型
● 元组
结论
● 组件是可重用代码
的一种方式
● 组件是需要传统和语言
支持
● D的许多高级特征
可结合来支持组件
● 在文件和过滤,流及stl
的早期成功基础上构建.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现