自从踏上AI辅助开发这条不归路,就回不了头,只能勇往直前!就算是简单的智能提示、补充代码、自动多语言补全等功能,就已经让你离不开它,更何况强大的代码生成成功。如果还没有开始使用AI辅助开发,那么赶快为自己的开发工具安装一个免费的AI助手,基本上目前流行的开发工具都会有对应的免费的辅助AI插件。
对于第一次使用AI辅助开发的开发者,记住一点:给出的问题,也就是需求,越详细,AI给的代码就越完整,功能也完善。本文将通过一个实例来探讨如何让AI助手生成满意的代码。
本文的开发环境为vs code
,AI助手将使用Fitten Code
扩展。安装完Fitten Code
后,会在主侧边栏显示一个Fitten Code
的图标,切换到Fitten Code
,在底部会有一个输入框,输入想要的问题就能生成所需的代码。
现在,在输入框输入“使用Typescript创建一个仓储用来获取远程数据”并按回车发送,将会看到以下返回信息:
从生成的Repository
类可以看到,已经生成了getAll
和getById
方法,并建议添加create
、update
和delete
等方法。当然,你应该不会满足于此,获取数据时,分页、过滤和高级过滤等等功能还没添加,建议的三个方法也生成,这时候,就需要列一个详细的需求给它,让它生成更完整的代码。
下面在输入框输入以下需求:
使用Typescript创建一个仓储类用来获取远程数据并具有以下功能:
* 获取传递给构造函数的配置项pageSizes的第一数据作为当前的pageSize,并添加setPageSize方法来设置设置当前的pageSize,要验证设置的pageSize是否在pageSizes中,pageSize改变后,重新加载数据。添加getPageSize方法来获取当前的pageSize。
* 添加setPage方法来设置当前页,当前页改变后,重新加载数据。添加getPage方法来获取当前页,
* 添加filter方法来执行数据过滤
* 添加sort方法来对数据进行排序
* 添加search方法来对数据进行高级过滤
* 添加getTotal方法来获取记录总数
* 添加getPages方法来获取总页数
* 添加load方法来获取远程数据,在执行远程加载前,如果在构造函数中传入了beforeLoad函数,则先执行beforeLoad,如果返回false,则不执行数据加载。如果可以加载数据,则先调用getParams方法整合分页、过滤、高级过滤等数据,为加载数据提供参数。在数据加载后,如果从构造函数中传入了afterLoad函数,则执行afterLoad函数,然后触发laod事件。
* 添加create方法用来保存新记录
* 添加update方法用来更新记录
* 添加delete方法用来删除记录
* 添加一个方法用来获取单一数据
等待一会就会得到以下代码:
import axios, { AxiosResponse } from 'axios';
interface RemoteData {
id: number;
name: string;
// 其他字段...
}
interface RepositoryConfig {
baseUrl: string;
pageSizes: number[];
beforeLoad?: () => boolean;
afterLoad?: (data: RemoteData[]) => void;
}
class AdvancedRepository {
private baseUrl: string;
private pageSizes: number[];
private pageSize: number;
private page: number;
private total: number;
private data: RemoteData[];
private beforeLoad?: () => boolean;
private afterLoad?: (data: RemoteData[]) => void;
constructor(config: RepositoryConfig) {
this.baseUrl = config.baseUrl;
this.pageSizes = config.pageSizes;
this.pageSize = config.pageSizes[0];
this.page = 1;
this.total = 0;
this.data = [];
this.beforeLoad = config.beforeLoad;
this.afterLoad = config.afterLoad;
}
public setPageSize(size: number): void {
if (!this.pageSizes.includes(size)) {
throw new Error('Invalid page size');
}
this.pageSize = size;
this.load();
}
public getPageSize(): number {
return this.pageSize;
}
public setPage(page: number): void {
this.page = page;
this.load();
}
public getPage(): number {
return this.page;
}
public filter(filterFn: (item: RemoteData) => boolean): void {
this.data = this.data.filter(filterFn);
}
public sort(sortFn: (a: RemoteData, b: RemoteData) => number): void {
this.data.sort(sortFn);
}
public search(searchFn: (item: RemoteData) => boolean): void {
this.data = this.data.filter(searchFn);
}
public getTotal(): number {
return this.total;
}
public getPages(): number {
return Math.ceil(this.total / this.pageSize);
}
public async load(): Promise<void> {
if (this.beforeLoad && !this.beforeLoad()) {
return;
}
const params = this.getParams();
try {
const response: AxiosResponse<{ data: RemoteData[]; total: number }> = await axios.get(`${this.baseUrl}/data`, { params });
this.data = response.data.data;
this.total = response.data.total;
if (this.afterLoad) {
this.afterLoad(this.data);
}
// 触发load事件
} catch (error) {
console.error('Error fetching data:', error);
throw error;
}
}
private getParams(): any {
return {
page: this.page,
pageSize: this.pageSize,
// 其他参数...
};
}
public async create(data: RemoteData): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.post(`${this.baseUrl}/data`, data);
this.load();
return response.data;
} catch (error) {
console.error('Error creating data:', error);
throw error;
}
}
public async update(id: number, data: RemoteData): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.put(`${this.baseUrl}/data/${id}`, data);
this.load();
return response.data;
} catch (error) {
console.error('Error updating data:', error);
throw error;
}
}
public async delete(id: number): Promise<void> {
try {
await axios.delete(`${this.baseUrl}/data/${id}`);
this.load();
} catch (error) {
console.error('Error deleting data:', error);
throw error;
}
}
public async getById(id: number): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.get(`${this.baseUrl}/data/${id}`);
return response.data;
} catch (error) {
console.error(`Error fetching data with id ${id}:`, error);
throw error;
}
}
}
// 使用示例
const repo = new AdvancedRepository({
baseUrl: 'https://api.example.com',
pageSizes: [10, 20, 50],
beforeLoad: () => {
// 执行一些预加载逻辑
return true;
},
afterLoad: (data) => {
console.log('Data loaded:', data);
}
});
repo.load().then(() => {
console.log('Data loaded');
}).catch(error => {
console.error('Error:', error);
});
虽然代码不尽人意,但起码已具雏形。这时候你的选择可以是重新组织需求,再次生成,或者选择全部代码,在选择代码上单击鼠标右键,在右键菜单中选择Fitten Code - 开始聊天
,然后在输入框中输入:
在filter方法中,用filter属性记录当前过滤值,然后重新调用load方法。sort和search方法与fitler方法类似。在数据加载后,从data中获取记录, 如果有afterLoad函数,则将afterLoad函数返回值作为data属性的值,在更新total后,根据pageSize重新计算pages。
以下是返回的代码:
import axios, { AxiosResponse } from 'axios';
interface RemoteData {
id: number;
name: string;
// 其他字段...
}
interface RepositoryConfig {
baseUrl: string;
pageSizes: number[];
beforeLoad?: () => boolean;
afterLoad?: (data: RemoteData[]) => void;
}
class Repository {
private baseUrl: string;
private pageSizes: number[];
private pageSize: number;
private page: number;
private total: number;
private data: RemoteData[];
private beforeLoad?: () => boolean;
private afterLoad?: (data: RemoteData[]) => void;
private filterFn?: (item: RemoteData) => boolean;
private sortFn?: (a: RemoteData, b: RemoteData) => number;
private searchFn?: (item: RemoteData) => boolean;
constructor(config: RepositoryConfig) {
this.baseUrl = config.baseUrl;
this.pageSizes = config.pageSizes;
this.pageSize = config.pageSizes[0];
this.page = 1;
this.total = 0;
this.data = [];
this.beforeLoad = config.beforeLoad;
this.afterLoad = config.afterLoad;
}
public setPageSize(size: number): void {
if (!this.pageSizes.includes(size)) {
throw new Error('Invalid page size');
}
this.pageSize = size;
this.load();
}
public getPageSize(): number {
return this.pageSize;
}
public setPage(page: number): void {
this.page = page;
this.load();
}
public getPage(): number {
return this.page;
}
public filter(filterFn: (item: RemoteData) => boolean): void {
this.filterFn = filterFn;
this.load();
}
public sort(sortFn: (a: RemoteData, b: RemoteData) => number): void {
this.sortFn = sortFn;
this.load();
}
public search(searchFn: (item: RemoteData) => boolean): void {
this.searchFn = searchFn;
this.load();
}
public getTotal(): number {
return this.total;
}
public getPages(): number {
return Math.ceil(this.total / this.pageSize);
}
public async load(): Promise<void> {
if (this.beforeLoad && !this.beforeLoad()) {
return;
}
const params = this.getParams();
try {
const response: AxiosResponse<{ data: RemoteData[]; total: number }> = await axios.get(`${this.baseUrl}/data`, { params });
let data = response.data.data;
if (this.filterFn) {
data = data.filter(this.filterFn);
}
if (this.sortFn) {
data.sort(this.sortFn);
}
if (this.searchFn) {
data = data.filter(this.searchFn);
}
this.data = data;
this.total = response.data.total;
if (this.afterLoad) {
this.data = this.afterLoad(this.data);
}
} catch (error) {
console.error('Error fetching data:', error);
throw error;
}
}
private getParams(): any {
return {
page: this.page,
pageSize: this.pageSize,
// 其他参数...
};
}
public async create(data: RemoteData): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.post(`${this.baseUrl}/data`, data);
this.load();
return response.data;
} catch (error) {
console.error('Error creating data:', error);
throw error;
}
}
public async update(id: number, data: RemoteData): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.put(`${this.baseUrl}/data/${id}`, data);
this.load();
return response.data;
} catch (error) {
console.error('Error updating data:', error);
throw error;
}
}
public async delete(id: number): Promise<void> {
try {
await axios.delete(`${this.baseUrl}/data/${id}`);
this.load();
} catch (error) {
console.error('Error deleting data:', error);
throw error;
}
}
public async getById(id: number): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.get(`${this.baseUrl}/data/${id}`);
return response.data;
} catch (error) {
console.error(`Error fetching data with id ${id}:`, error);
throw error;
}
}
}
从返回的代码可以看到,AI还是没完全领会,filter等是作为远程参数去获取数据,还是只做了本地过滤,这也只能怪自己没把需求说清楚。重复选择代码,开始聊天的操作并输入:
在getParams中整合filter、sort、search等信息作为远程查询的参数,而不是对返回的数据执行过滤和排序
以下是更新好的代码:
import axios, { AxiosResponse } from 'axios';
interface RemoteData {
id: number;
name: string;
// 其他字段...
}
interface RepositoryConfig {
baseUrl: string;
pageSizes: number[];
beforeLoad?: () => boolean;
afterLoad?: (data: RemoteData[]) => void;
}
class Repository {
private baseUrl: string;
private pageSizes: number[];
private pageSize: number;
private page: number;
private total: number;
private data: RemoteData[];
private beforeLoad?: () => boolean;
private afterLoad?: (data: RemoteData[]) => void;
private filterParams?: any;
private sortParams?: any;
private searchParams?: any;
constructor(config: RepositoryConfig) {
this.baseUrl = config.baseUrl;
this.pageSizes = config.pageSizes;
this.pageSize = config.pageSizes[0];
this.page = 1;
this.total = 0;
this.data = [];
this.beforeLoad = config.beforeLoad;
this.afterLoad = config.afterLoad;
}
public setPageSize(size: number): void {
if (!this.pageSizes.includes(size)) {
throw new Error('Invalid page size');
}
this.pageSize = size;
this.load();
}
public getPageSize(): number {
return this.pageSize;
}
public setPage(page: number): void {
this.page = page;
this.load();
}
public getPage(): number {
return this.page;
}
public filter(filterParams: any): void {
this.filterParams = filterParams;
this.load();
}
public sort(sortParams: any): void {
this.sortParams = sortParams;
this.load();
}
public search(searchParams: any): void {
this.searchParams = searchParams;
this.load();
}
public getTotal(): number {
return this.total;
}
public getPages(): number {
return Math.ceil(this.total / this.pageSize);
}
public async load(): Promise<void> {
if (this.beforeLoad && !this.beforeLoad()) {
return;
}
const params = this.getParams();
try {
const response: AxiosResponse<{ data: RemoteData[]; total: number }> = await axios.get(`${this.baseUrl}/data`, { params });
this.data = response.data.data;
this.total = response.data.total;
if (this.afterLoad) {
this.data = this.afterLoad(this.data);
}
} catch (error) {
console.error('Error fetching data:', error);
throw error;
}
}
private getParams(): any {
const params: any = {
page: this.page,
pageSize: this.pageSize,
// 其他参数...
};
if (this.filterParams) {
Object.assign(params, this.filterParams);
}
if (this.sortParams) {
Object.assign(params, this.sortParams);
}
if (this.searchParams) {
Object.assign(params, this.searchParams);
}
return params;
}
public async create(data: RemoteData): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.post(`${this.baseUrl}/data`, data);
this.load();
return response.data;
} catch (error) {
console.error('Error creating data:', error);
throw error;
}
}
public async update(id: number, data: RemoteData): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.put(`${this.baseUrl}/data/${id}`, data);
this.load();
return response.data;
} catch (error) {
console.error('Error updating data:', error);
throw error;
}
}
public async delete(id: number): Promise<void> {
try {
await axios.delete(`${this.baseUrl}/data/${id}`);
this.load();
} catch (error) {
console.error('Error deleting data:', error);
throw error;
}
}
public async getById(id: number): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.get(`${this.baseUrl}/data/${id}`);
return response.data;
} catch (error) {
console.error(`Error fetching data with id ${id}:`, error);
throw error;
}
}
}
如果觉得代码还是不太满意,可以继续重复以下操作更改代码直到满意,还可以选择代码后,在选择代码上单击鼠标右键选择Fitter Code - 优化代码
,让它自己去优化代码,返回结果如下:
import axios, { AxiosResponse } from 'axios';
interface RemoteData {
id: number;
name: string;
// 其他字段...
}
interface RepositoryConfig {
baseUrl: string;
pageSizes: number[];
beforeLoad?: () => boolean;
afterLoad?: (data: RemoteData[]) => void;
}
class Repository {
private baseUrl: string;
private pageSizes: number[];
private pageSize: number;
private page: number;
private total: number;
private data: RemoteData[];
private beforeLoad?: () => boolean;
private afterLoad?: (data: RemoteData[]) => void;
private filterParams?: any;
private sortParams?: any;
private searchParams?: any;
constructor(config: RepositoryConfig) {
this.baseUrl = config.baseUrl;
this.pageSizes = config.pageSizes;
this.pageSize = config.pageSizes[0];
this.page = 1;
this.total = 0;
this.data = [];
this.beforeLoad = config.beforeLoad;
this.afterLoad = config.afterLoad;
}
public setPageSize(size: number): void {
if (!this.pageSizes.includes(size)) {
throw new Error('Invalid page size');
}
this.pageSize = size;
this.load();
}
public getPageSize(): number {
return this.pageSize;
}
public setPage(page: number): void {
this.page = page;
this.load();
}
public getPage(): number {
return this.page;
}
public filter(filterParams: any): void {
this.filterParams = filterParams;
this.load();
}
public sort(sortParams: any): void {
this.sortParams = sortParams;
this.load();
}
public search(searchParams: any): void {
this.searchParams = searchParams;
this.load();
}
public getTotal(): number {
return this.total;
}
public getPages(): number {
return Math.ceil(this.total / this.pageSize);
}
public async load(): Promise<void> {
if (this.beforeLoad && !this.beforeLoad()) {
return;
}
const params = this.getParams();
try {
const response: AxiosResponse<{ data: RemoteData[]; total: number }> = await axios.get(`${this.baseUrl}/data`, { params });
this.data = response.data.data;
this.total = response.data.total;
if (this.afterLoad) {
this.data = this.afterLoad(this.data);
}
} catch (error) {
console.error('Error fetching data:', error);
throw error;
}
}
private getParams(): any {
const params: any = {
page: this.page,
pageSize: this.pageSize,
// 其他参数...
};
if (this.filterParams) {
Object.assign(params, this.filterParams);
}
if (this.sortParams) {
Object.assign(params, this.sortParams);
}
if (this.searchParams) {
Object.assign(params, this.searchParams);
}
return params;
}
public async create(data: RemoteData): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.post(`${this.baseUrl}/data`, data);
this.load();
return response.data;
} catch (error) {
console.error('Error creating data:', error);
throw error;
}
}
public async update(id: number, data: RemoteData): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.put(`${this.baseUrl}/data/${id}`, data);
this.load();
return response.data;
} catch (error) {
console.error('Error updating data:', error);
throw error;
}
}
public async delete(id: number): Promise<void> {
try {
await axios.delete(`${this.baseUrl}/data/${id}`);
this.load();
} catch (error) {
console.error('Error deleting data:', error);
throw error;
}
}
public async getById(id: number): Promise<RemoteData> {
try {
const response: AxiosResponse<RemoteData> = await axios.get(`${this.baseUrl}/data/${id}`);
return response.data;
} catch (error) {
console.error(`Error fetching data with id ${id}:`, error);
throw error;
}
}
}
在通过手动和互动等方法完成代码后,就可以让AI帮忙生成完整的单元测试代码,获得最终的代码了。
从以上的探讨过程可以看到,AI还不能做到尽善尽美,但已经可以大大提高开发效率了。不过要注意的是,有时候AI会陷入死循环,譬如说A这样会导致问题B,然后它去改,问题B解决了,但会出现A的问题没有解决,然后它就进入死循环,A和B来回切换,这时候,就要换个思路了,不要和它继续纠缠下去,不然会很累。可行的办法有换个解决问题的思路,或者找其他免费的AI辅助,如千义通问等等,这些AI各具特色,有自己擅长的东西,多问几个,会获得更精准的解决方案。笔者觉得更重要的是,提高自己的设计能力和需求讲述能力,将可大大释放AI的能力。