从泡茶艺术到编程智慧:模板方法模式
在编程的长河中,传统经典编程与新兴的人工智能生成内容(AIGC)正携手共舞,共同编织着技术发展的新篇章。在本文中我将通过一项日常活动——泡茶,探索JavaScript原型式面向对象的编程,并介绍传统经典设计模式里的模板方法模式。
泡一杯茶
今天,让我们一起静下心来,去泡一杯茶;泡一杯茶很容易,首先我们需要把水烧开,在等待期间,拿一个杯子并把茶包放进去,一旦水开了,就把它倒在茶包上,等待一会儿,让茶叶浸泡,几分钟后,取出茶包,如果你愿意,可以加一些糖和牛奶调味,就这样,您可以享受一杯美味的茶了。
从上面的描述中,我们可以把泡茶分为以下步骤:
- 把水煮沸
- 用沸水浸泡茶叶
- 把茶水倒进杯子
- 加柠檬
泡茶,这一看似简单的日常行为,却蕴含了程序设计中的基本原理和流程控制。无论是把水烧开,还是茶叶的浸泡,每一步都像是编程中的一个方法调用,串联起来便形成了一套完整的“算法”。
传统面向对象
在传统的面向对象编程语言中,如Java、C#或Python等,类(Class)的定义通常包含了构造函数(constructor)、方法列表、以及属性的get/set方法,同时也支持public(公共)和private(私有)访问修饰符来控制成员的可见性。
原型式面向对象
在js中采用的是原型式的面向对象,那何为原型?原型式面向对象(Prototype-based Object-Oriented Programming,简称 Prototype-based OOP)是一种编程范式,与经典的基于类(Class-based)的面向对象编程不同。在原型式面向对象中,对象可以直接从其他的对象继承属性和方法,而无需通过类作为中介。这种模型的核心思想是“万物皆对象”,每个对象都有一个可被其他对象继承的原型(prototype)。
基于这种思想,我们就可以编写泡茶的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模板方法模式</title>
</head>
<body>
<script>
// 茶类 首字母大写,es5
// js 变量类型是由值来决定的
// js 除了简单数据类型,就是对象(函数是可执行的对象)
// js 早期没有class 关键字
// js 普通函数,
// 大写就是 构造函数
// 其实JS里面没有类 早期没有提供class
// Tea 和 绿茶之间没有血缘关系,Tea 是原型对象,
// Tea 是可执行的对象,构建我们的对象 this指向的这些属性就是实例的属性模板
// Tea 通过prototype 添加一些方法,都可以以它为原型的对象共享(public)
function Tea(type) {
this.type = type
console.log('您准备泡一杯'+ this.type);
}
// 对象 prototype 添加方法
Tea.prototype.boilWater = function () {
console.log('把水煮沸');
}
Tea.prototype.steepTeaBag = function () {
console.log('用沸水浸泡茶叶');
}
Tea.prototype.pourInCup = function () {
console.log('把茶水倒进杯子');
}
Tea.prototype.addLemon = function () {
console.log('加柠檬');
}
// // 当以new 的方式被运行
// var greenTea = new Tea('绿茶');
// var wlTea = new Tea('乌龙茶');
var lemonTea = new Tea('柠檬茶');
lemonTea.boilWater();
lemonTea.steepTeaBag();
lemonTea.pourInCup();
lemonTea.addLemon();
</script>
</body>
</html>
在上面的代码中,我们创建了茶类Tea
的构造函数function Tea(type)
;用构造函数我们可以实例化出来一个柠檬茶的对象lemonTea
;我们再往Tea
的原型对象上添加boilWater、steepTeaBag、pourInCup、addLemon
四个方法,这样实例化对象lemonTea
就能访问到原型上的方法完成泡茶。
模板方法模式
在JavaScript中,模板方法模式是一种行为设计模式,它定义了一个操作中的算法骨架,而将一些步骤延迟到子类中实现。模板方法使得子类可以重用父类定义的算法结构,但又允许它们重新定义某些步骤。
在上面的代码中,我们能看到,每次实例化对象时,都要重新调用一遍泡茶的方法;这种情况我们就可以利用模板方法模式,把子类共用的方法写到一个模板方法上,最后只需要调用这个模板方法就好了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模板方法模式</title>
</head>
<body>
<script>
// 茶类 首字母大写,es5
// js 变量类型是由值来决定的
// js 除了简单数据类型,就是对象(函数是可执行的对象)
// js 早期没有class 关键字
// js 普通函数,
// 大写就是 构造函数
// 其实JS里面没有类 早期没有提供class
// Tea 和 绿茶之间没有血缘关系,Tea 是原型对象,
// Tea 是可执行的对象,构建我们的对象 this指向的这些属性就是实例的属性模板
// Tea 通过prototype 添加一些方法,都可以以它为原型的对象共享(public)
function Tea(type) {
this.type = type
console.log('您准备泡一杯'+ this.type);
}
// 对象 prototype 添加方法
Tea.prototype.boilWater = function () {
console.log('把水煮沸');
}
Tea.prototype.steepTeaBag = function () {
console.log('用沸水浸泡茶叶');
}
Tea.prototype.pourInCup = function () {
console.log('把茶水倒进杯子');
}
Tea.prototype.addLemon = function () {
console.log('加柠檬');
}
// 接口,
Tea.prototype.init = function () {
this.boilWater();
this.steepTeaBag();
this.pourInCup();
this.addLemon();
console.log('茶泡好了');
}
// // 当以new 的方式被运行
// var greenTea = new Tea('绿茶');
// var wlTea = new Tea('乌龙茶');
var lemonTea = new Tea('柠檬茶');
lemonTea.init();
</script>
</body>
</html>
在这段代码中,Tea
构造函数及其原型上的方法共同构成了模板方法模式的实现:
- 模板方法 (
init
函数) : 在Tea
原型上的init
方法定义了一个泡茶的基本步骤序列,包括煮水、浸泡茶叶、倒进杯子和加柠檬,最后通知茶泡好了。这是模板方法模式中的“模板方法”,它定义了一个固定的算法结构。
Tea.prototype.init = function () {
this.boilWater();
this.steepTeaBag();
this.pourInCup();
this.addLemon();
console.log('茶泡好了');
}
- 基本操作 (
boilWater
,steepTeaBag
,pourInCup
,addLemon
) : 这些方法代表了算法中的基本操作,它们在init
方法中被调用,定义了泡茶的具体步骤。在这个例子中,所有的操作都是在Tea
原型上定义的,意味着所有由Tea
构造函数实例化的对象都将共享这些基本操作。
面向大模型的AIGC编程
像以上的分步式,流程控制类的问题,传统编程能解决,大模型的AIGC编程也能够解决,而且对于后者来说,这种问题可能都是降维打击。接下来,给大家演示一下大模型是怎么解决的:
require('dotenv').config();
const OpenAI = require('openai')
const client = new OpenAI({
apiKey: process.env.OPENAI_KEY,
baseURL:'https://api.chatanywhere.tech/v1'
})
const getChatResponse = async function(model,prompt,n){
const response = await client.chat.completions.create({
model:model, // 适合聊天的模型 有很多种
messages: [{
role : 'user',
content : prompt
}]
})
return response.choices[0].message.content;
}
const main = async () => {
//AIGC 优势就是处理文本,生成内容
const text = `
泡一杯茶很容易,首先需要把水烧开,
在等待期间,拿一个杯子并把茶包放进去,
一旦水开了,就把它倒在茶包上,
等待一会儿,让茶叶浸泡,几分钟后,取出茶包,
如果你愿意,可以加一些糖和牛奶调味,
就这样,您可以享受一杯美味的茶了。
`
const prompt = `
您将获得由三个引号括起来的文本,
如果它包含一系列的指令,则需要按照以下格式重新编写这些指令,
第一步 - ...
第二步 - ...
...
第N步 - ...
如果文本中不包含一系列的指令,则直接写“未提供步骤”
"""${text}"""
`
const result = await getChatResponse('gpt-3.5-turbo',prompt)
console.log(result);
}
main();
流程控制是编程基础中的重要组成部分,用于指导程序的执行顺序、循环、分支等逻辑。传统编程中,程序员通过编写精确的逻辑指令来实现流程控制。而AIGC的介入,尤其是通过提示(prompt engineering)来引导AI模型生成或执行特定任务,为流程控制提供了一种新的视角。
转载自:https://juejin.cn/post/7377901375001329727