您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

每个开发者都应该知道的七个原则

时间:2023-11-17 14:27:03  来源:微信公众号  作者:小技术君

软件开发是一门复杂的领域。是什么让高质量的软件与容易出错、充满错误的软件有所不同?答案通常在开发人员在编写代码时采用的核心原则中。

每个开发者都应该知道的七个原则

编程原则:优秀代码的基石

编程原则是卓越软件的基石。这些建议和最佳实践指导开发人员编写既功能强大又优雅、易维护和可扩展的代码。

在本文中,我们深入探讨了每个开发者工具包中都应该有的七个基本编程原则:

1. DRY 原则

DRY:不要重复自己 — 减少冗余的关键原则。如果你发现自己复制粘贴同一段代码超过两次,现在是考虑抽象的时候了。

考虑这种情况:你有三个函数,每个函数都以相同的方式格式化日期。与其在所有三个函数中都有重复的格式化代码,不如创建一个单一的辅助函数:

// 格式化日期的辅助函数
function formatDate(date) {  
  return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
}

// 函数 1: 显示今天的日期
function displayTodaysDate() {  
  const today = new Date();  
  return formatDate(today);
}

// 函数 2: 显示一周后的日期
function displayDateOneWeekFromNow() {  
  const oneWeekFromNow = new Date();  
  oneWeekFromNow.setDate(oneWeekFromNow.getDate() + 7);  
  return formatDate(oneWeekFromNow);
}

// 函数 3: 显示一个月前的日期
function displayDateOneMonthAgo() {  
  const oneMonthAgo = new Date();  
  oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);  
  return formatDate(oneMonthAgo);

2. KISS 原则

KISS:保持简单,愚蠢 — 在你的代码中追求简单。例如,如果你写了一个复杂的 if-else 链,也许使用 switch 语句或字典会简化和美化结构:

之前:

function getErrorMessage(errorCode) {  
  if (errorCode = 'E001') {  
    return 'Invalid input.';  
  } else if (errorCode = 'E002') {  
    return 'Connection timed out.';  
  } else if (errorCode = 'E003') {  
    return 'Database error.';  
  } else if (errorCode = 'E004') {  
    return 'File not found.';  
  } else {  
    return 'Unknown error.';  
  }
}

重构后:

const ERROR_MESSAGES = {  
  'E001': 'Invalid input.',  
  'E002': 'Connection timed out.',  
  'E003': 'Database error.',  
  'E004': 'File not found.'
};

function getErrorMessage(errorCode) {  
  return ERROR_MESSAGES[errorCode] || 'Unknown error.';
}

3. SOLID 原则

SOLID 不是一个单一的原则,而是五个设计原则的集合。尽管它们根植于面向对象编程(OOP),但它们的智慧可以更广泛地应用。

(1) 单一职责原则(SRP): 一个类应该只有一个改变的理由。这意味着每个类应该只有一个任务或功能,确保更容易维护和在更改过程中减少副作用。

考虑这个例子:

// 错误的方法

class UserManager {  
  saveUser(user) {  
    // 保存用户到数据库的逻辑  
  }

  generateReport(user) {  
    // 生成用户报告的逻辑  
  }
}

更优雅的解决方案是将其拆分为两个各自处理单一职责的类:

// 正确的方法

class UserDatabase {  
  save(user) {  
    // 将用户数据保存到数据库  
  }
}

class UserReport {  
  generate(user) {  
    // 为用户生成报告  
  }
}

在上面的代码片段中,我们分担了责任:UserReport 处理用户的报告生成,而 UserDatabase 管理将用户数据保存到数据库。

(2) 开闭原则(OCP): 软件组件应该对扩展开放,对修改关闭。这允许开发人员在不修改现有代码的情况下添加新功能,促进可重用性并减少错误。

假设你有一个 AreaCalculator 类,用于计算矩形的面积。现在,如果我们添加一个 Circle,AreaCalculator 将需要修改。

// 错误的方法

class AreaCalculator {  
  calculateArea(shape) {  
    if (shape.type = "circle") {  
      return 3.14 * shape.radius * shape.radius;  
    } else if (shape.type = "square") {  
      return shape.side * shape.side;  
    }  
  }
}

相反,使用 OCP:我们从一个基础的 Shape 类扩展我们的形状,允许轻松添加新形状而不修改 AreaCalculator。

// 正确的方法

class Shape {  
  calculateArea() {}
}

class Circle extends Shape {  
  constructor(radius) {  
    super();  
    this.radius = radius;  
  }

  calculateArea() {  
    return 3.14 * this.radius * this.radius;  
  }
}

class Square extends Shape {  
  constructor(side) {  
    super();  
    this.side = side

;  
  }

  calculateArea() {  
    return this.side * this.side;  
  }
}

(3) 里氏替换原则(LSP): 子类应该能够替换其基类而不产生异常。这确保继承类保持其父类的属性和行为。

遵循 LSP,我们应该重构设计以确保正确的继承:

class Bird {  
  fly() {  
    // 通用飞行行为  
  }
}

class Penguin extends Bird {  
  // 企鹅不能飞,所以这个方法不应该在这里
}

正确的方法是我们将形状从基本的 Shape 类扩展出来,允许轻松添加新的形状而不修改 AreaCalculator。

(4) 接口隔离原则(ISP): 类不应该被迫实现它们不使用的接口。相反,接口应该对其目的具体而清晰。

这意味着接口不应该有太多方法,尽量我们将小接口抽取出来,以便类可以只实现它们需要的接口,就像下面的例子:

// 错误的方法

interface Worker {  
  work();  
  eat();  
  sleep();  
  swim();
}

// 正确的方法

interface Worker {  
  work();
}

interface Eater {  
  eat();
}

interface Swimmer {  
  swim();
}

(5) 依赖反转原则(DIP): 高层模块不应与低层模块纠缠在一起;它们都应依赖于抽象。例如在开关和设备的设计中可以找到:

// 错误的方法

class LightBulb {  
  turnOn() {}  
  turnOff() {}
}

class Switch {  
  constructor(bulb) {  
    this.bulb = bulb;  
  }

  operate() {  
    // 直接控制灯泡  
  }
}

我们可以重构这样,以便 Switch 可以对任何实现 SwitchableDevice 的设备进行操作,而不仅仅是 LightBulb。

// 正确的方法

class SwitchableDevice {  
  turnOn() {}  
  turnOff() {}
}

class Bulb extends SwitchableDevice {  
  // 实现 turnOn 和 turnOff 方法  
}

class SwitchDIP {  
  constructor(device) {  
    this.device = device;  
  }

  operate() {  
    // 控制设备  
  }
}

4. YAGNI 原则

YAGNI,“你不会需要它”,警告不要在必要之前添加功能。

例如,如果你正在构建一个博客网站,并考虑添加一个基于用户写作的功能来预测用户的心情,但这对于网站正常运行并不是必需的,那么最好将其留在一边,至少现在是这样。

有不必要功能的应用:

class Blog {  
  constructor(posts) {  
    this.posts = posts;  
  }

  addPost(post) {  
    this.posts.push(post);  
  }

  displayPosts() {  
    // 显示所有帖子  
  }

  predictUserMoodBasedOnWritings(post) {  
    // 预测情绪的复杂算法  
    // ...  
    return "HAppy"; // 只是一个示例情绪  
  }

  notifyUserAboutMood(mood) {  
    // 通知逻辑  
    console.log(`Based on your writing, you seem to be ${mood}`);  
  }
}

删除不必要功能后:

class Blog {  
  constructor(posts) {  
    this.posts = posts;  
  }

  addPost(post) {  
    this.posts.push(post);  
  }

  displayPosts() {  
    // 显示所有帖子  
  }
}

5. SoC 原则

SoC,或“关注点分离”,建议不同的功能区域应由不同且最小重叠的模块管理。

例如,在一个天气应用程序中,一个模块可以处理数据获取,另一个可以管理数据存储,另一个则可以控制用户界面。每个都有自己的关注点,与其他模块分开。

// 1. 数据获取模块

function fetchWeatherData(city) {  
  const apiKey = 'YOUR_API_KEY';  
  const response = fetch(`https://api.weather.com/v1/${city}?apiKey=${apiKey}`);  
  return response.json();
}

// 2. 数据存储模块

function storeWeatherData(data) {  
  localStorage.setItem('weatherData', JSON.stringify(data));
}

// 3. 用户界面模块

function displayWeatherData(data) {  
  const weatherBox = document.querySelector('#weather-box');  
  weatherBox.innerhtml = `<h1>${data.city}</h1><p>${data.temperature}°C</p>`;
}

// 在主应用程序函数中组合它们

function weatherApp(city) {  
  const data = fetchWeatherData(city);  
  storeWeatherData(data);  
  displayWeatherData(data);
}

6. LoD 原则

LoD(迪米特法则)是开发软件的一个指导原则,特别是面向对象的程序。在其一般形式中,LoD是松散耦合的一个具体案例。

想象一下餐厅的场景:顾客将订单(方法)交给服务员,然后服务员将订单交给厨师。顾客不直接与厨师互动。

class Customer {
  constructor(wAIter) {
    this.waiter = waiter;
  }

  giveOrder(order) {
    console.log("Customer: I'd like to order " + order);
    this.waiter.takeOrder(order);
  }
}

class Waiter {
  constructor(chef) {
    this.chef = chef;
  }

  takeOrder(order) {
    console.log('Waiter: Order received - ' + order);
    this.chef.prepareOrder(order);
  }
}

class Chef {
  prepareOrder(order) {
    console.log('Chef: Preparing ' + order);
    // Logic to prepare the food...
  }
}

7. COI 原则

组合优于继承原则(COI)建议使用组合(将简单对象组合以创建更复杂的对象)而不是类继承。

想象一下你有一个类 Bird 和一个类 Airplane。它们都能飞,但有继承关系并不合理。相反,你可以有一个 CanFly 类,并将你的 Bird 和 Airplane 类与它组合。

// 错误的方法:继承

class CanFly {
  fly() {
    console.log(this.constructor.name + ' is flying!');
  }
}

class BirdInherit extends CanFly {}

class AirplaneInherit extends CanFly {}

通过以下组合方法,你可以轻松地向 BirdCompose 或 AirplaneCompose 添加或删除功能,而无需进行结构更改或添加不必要的冗余,强调灵活性。

// 正确的方法:组合

class CanFlyComposition {
  fly() {
    console.log('Flying in the sky!');
  }
}

class BirdCompose {
  constructor() {
    this.flyingCapability = new CanFlyComposition();
  }

  fly() {
    this.flyingCapability.fly();
  }
}

class AirplaneCompose {
  constructor() {
    this.flyingCapability = new CanFlyComposition();
  }

  fly() {
    this.flyingCapability.fly();
  }
}


Tags:开发者   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
WWDC24苹果开发者大会定档端午节 高管暗示或有AI内容
3月27日,苹果宣布将于6月10日至14日在线举行年度全球开发者大会(WWDC)。开发者与学生们将有机会于大会开幕当天参与在Apple Park举办的线下特别活动。6月10日,大会的第一天也是...【详细内容】
2024-03-27  Search: 开发者  点击:(10)  评论:(0)  加入收藏
开发者再分享 OpenAI Sora 生成的短视频:树叶大象、彩虹瀑布等
IT之家 3 月 19 日消息,OpenAI 今年 2 月推出 Sora 模型之后,迅速成为 AI 圈内头条,能够基于用户的一句话,生成最长 1 分钟的视频,效果接近实拍。OpenAI 目前并未向公众发布 Sora...【详细内容】
2024-03-19  Search: 开发者  点击:(12)  评论:(0)  加入收藏
提供镜像内容,谷歌上线 Chrome for Developers 中国开发者 .cn 域名网站
IT之家 3 月 5 日消息,据谷歌“谷歌开发者”官方公众号,目前用户可以通过 .cn 域名访问 web.dev 和 Chrome for Developers 网站,官方宣称将在相关域名“提供所有镜像后的内容...【详细内容】
2024-03-06  Search: 开发者  点击:(17)  评论:(0)  加入收藏
Win + Ubuntu 缝合怪:第三方开发者推出“Wubuntu”Linux 发行版
IT之家 2 月 26 日消息,一位第三方开发者推出了一款名为“Wubuntu”的缝合怪 Linux 发行版,系统本身基于 Ubuntu,但界面为微软 Windows 11 风格,甚至存在微软 Windows 徽标。据...【详细内容】
2024-02-27  Search: 开发者  点击:(47)  评论:(0)  加入收藏
开发者的Kubernetes懒人指南
你可以将本文作为开发者快速了解 Kubernetes 的指南。从基础知识到更高级的主题,如 Helm Chart,以及所有这些如何影响你作为开发者。译自Kubernetes for Lazy Developers。作...【详细内容】
2024-02-01  Search: 开发者  点击:(50)  评论:(0)  加入收藏
Python开发者必备的八个PyCharm插件
在编写代码的过程中,括号几乎无处不在,以至于有时我们会拼命辨别哪个闭合括号与哪个开头的括号相匹配。这款插件能帮助解决这个众所周知的问题。前言在PyCharm中浏览插件列表...【详细内容】
2024-01-26  Search: 开发者  点击:(84)  评论:(0)  加入收藏
开发者如何使用Postgres扩展,包括AI应用?
作者 | Richard MacManus编译 | 言征一家名为Tembo的公司鼓励开发人员在Postgres之上进行构建,使用越来越多的Postgres扩展。PostgreSQL(通常称为Postgres)是一个流行的免费开...【详细内容】
2024-01-24  Search: 开发者  点击:(49)  评论:(0)  加入收藏
“AI女友”霸占GPT商店,OpenAI苦不堪言:开发者也难出头!
作者|TinaOpenAI 不久前推出了 GPT 商店,让开发者可以售卖自己定制的 GPT 机器人。商店刚开张,就积累了 300 万个不同类型的机器人。OpenAI 将该商店定位为一个聊天机器人交易...【详细内容】
2024-01-17  Search: 开发者  点击:(78)  评论:(0)  加入收藏
CUTOS边缘边缘计算操作系统-开发者平台体系结构
CUTOS为边缘现场、边缘云以及私有云的智能化系统建设提供了全面的基础平台支持。CUTOS的主要功能包括: LWA开发: CUTOS提供基于WEB技术的应用程序开发、运行和管理。 LWA使得...【详细内容】
2024-01-04  Search: 开发者  点击:(59)  评论:(0)  加入收藏
JavaScript开发者转向Rust的原因?
JavaScript开发者转向Rust的原因可能有很多,这里列出一些可能的原因: 性能: Rust是一种编译型语言,其性能通常优于JavaScript等解释型语言。对于需要处理大量数据或需要高并发的...【详细内容】
2024-01-04  Search: 开发者  点击:(96)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(5)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(12)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(8)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(10)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(8)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(5)  评论:(0)  加入收藏
站内最新
站内热门
站内头条