关于设计原则:面向对象的SOLID设计原则

在程序设计畛域,罗伯特·C·马丁指出了面向对象编程和面对对象设计的五大根本准则:SOLID。开发一个零碎时,如果利用这些准则,将会让零碎变得更加易于保护和扩大。 SOLID是由五个设计准则的首字母组成的: S - 繁多职责准则 - Single Responsibility PrincipleO - 凋谢关闭准则 - Open Close PrincipleL - 里氏替换准则 - Liskov Substitution PrincipleI - 接口拆散准则 - Interface Segregation PrincipleD - 依赖倒置准则 - Dependency Inversion Principle上面就SOLID五大设计准则,一起来看看。 S:繁多职责准则(Single Responsibility Principle)一个类(模块、函数等),只有一个职责;将多职责的类拆分为多个类,放弃各个类的互相独立。 益处:进步代码的可读性和可维护性,升高代码的复杂度,缩小批改代码的影响范畴。 任何代码都有可能批改。如果在一个类中实现多个不相干的职责,那么在批改其中一个职责的相干代码时,很有可能影响到其余职责的相干代码,造成这个类的不稳固影响范畴变大。 因而须要将多职责的类拆分为单职责的类,即便某一个职责相干代码须要批改,其影响范畴仅限于这个类,其余职责的代码不受这个职责代码批改的影响。 例如: // 一个光猫类,有两个职责:一个是治理连贯(dial和hangup);一个是数据传输(send和receive)class Model { dial (pno: string) {} hangup () {} send (msg: string) {} receive(data: string) {}}// 通常这两个职责并没有共同点,在一个类中实现,过于耦合。应该将其离开到两个绝对独立的类中,别离保护。class Connection { dial (pno: string) {} hangup () {}}class DataChannel { send (msg: string) {} receive(data: string) {}}class Model { constructor () { const connection = new Connection() const dataChannel = new DataChannel() }}O:凋谢关闭准则(Open Close Principle)当增加一个新的性能时,应该在已有代码的根底上扩大代码(新增模块、类、函数等),而不是批改已有的代码(批改模块、类、函数等)。 ...

May 10, 2023 · 2 min · jiezi

关于设计原则:代码设计原则

代码设计准则是用于进步代码品质、易读性和可维护性的规定和准则。它们的目标是使代码牢靠、易懂、易保护和易扩大。以下是一些罕用的代码设计准则: 1.繁多职责准则(Single Responsibility Principle):每个类或办法只负责一项工作,不应该有太多的职责。 2.开闭准则(Open/Closed Principle):对于扩大凋谢,对于批改敞开。类或模块应该能够扩大,但不应该批改已有的代码。 3.里氏替换准则(Liskov Substitution Principle):子类能够代替父类,并且不会导致任何谬误。 4.依赖倒置准则(Dependency Inversion Principle):高层模块不应该依赖低层模块,两者应该依赖其余形象层。 5.接口隔离准则(Interface Segregation Principle):客户端不应该依赖它不须要的接口。 6.合成复用准则(Composite Reuse Principle):通过合成复用来实现代码复用,而不是通过继承。 7.高内聚准则(High Cohesion Principle):每个类或模块应该有一个繁多的职责,且应该与其余局部相关联。 8.低耦合准则(Low Coupling Principle):各个模块之间的关系应该尽可能地低耦合,以缩小代码之间的相互影响。 9.可读性准则(Readability Principle):代码应该是易读的,通过正当的命名、缩进、空格等格局要求来进步代码的可读性。 10.可维护性准则(Maintainability Principle):代码应该是可保护的,通过良好的设计、正文等伎俩来进步代码的可维护性。 这些代码设计准则并不是强制执行的规定,而是倡议。在理论的开发中,依据我的项目的需要和理论状况抉择适合的准则,以保障代码的品质和易用性。

February 12, 2023 · 1 min · jiezi

关于设计原则:GRASP通用职责分配模式

在软件设计中构思对象的职责、角色和合作,须要用到一些准则和模式,GRASP九大准则 -> SOLID六大准则 -> GOF23种设计模式,GRASP处于最上层(更一般化的准则,不只利用于面向对象设计),SOLID准则再进一步细化,GOF再依据这些准则进一步的演绎出更具体的模式。 软件设计在实质上是为了管制复杂度,升高”软件的熵“。软件的复杂性在于除了要解决功能性需要,还要解决非功能性需要:可用性、可维护性、可扩展性、稳定性、高性能、数据一致性、容错性、可复用性、安全性、幂等性、兼容等等。 在常见的分层设计中,每一层都对下层屏蔽了外部的复杂度。同理,在类的设计中,类的复杂度也通过封装不蔓延到其余中央。 GRASP(General Responsibility Assignment Software Pattern),来源于:克雷·拉蒙.《Applying UML and Patterns》.1997,蕴含以下九个准则。 信息专家(Information Expert)定义:如果一个类领有执行某个职责所必须的信息,那么将这个职责调配给这个类。长处:升高了类间耦合,使信息(常识)没有蔓延进来。 创建者(Creator)谁应该负责创立一个类的实例?此模式答复了这个问题。定义:如果合乎上面的一个或者多个条件,则可将创立类A实例的职责调配给类B。1.B蕴含或聚合了A;2.B领有初始化A的数据,并把该数据在创立A的实例时传递给A;3.B记录A的实例;4.B频繁应用A;长处:升高了类间耦合,因为类B和类A曾经存在耦合,所以并没有减少额定的耦合。 低耦合耦合:评估一个零碎中各个元素(类,模块,子系统)之间的依赖水平。以下是一些耦合关系的体现:1.A具备一个B类型的属性(field);2.A调用了B的办法;3.A的办法蕴含对B的援用,比方办法参数为B,或返回类型为B;4.A是B的子类;5.B是一个接口,A实现了B接口;以上这些耦合关系越多代表耦合水平越高。这些关系简略地说就是A对B的“感知”。高耦合的毛病:一个类的批改会对其余类产生影响,容易产生脱漏和问题;零碎难以保护和了解,复用性也很差。升高耦合的一些办法:尽量减少对其余类的援用;进步办法和属性的拜访权限;尽量应用组合/聚合准则来代替继承;多态也是一种升高耦合的办法,调用者只须要晓得父类即可,不须要晓得所有子类型,升高了类型耦合。类间依赖是一种常见的耦合关系,尽量应用单向依赖,去除或弱化双向依赖,不应用循环依赖。 高内聚内聚:是对元素职责的相关性和集中度的度量。定义:即性能严密相干的职责应该放在一个类里,并共同完成无限的性能。与繁多职责和接口隔离准则是统一的。长处:类的性能高内聚后复杂性就升高了,保护老本也就随之升高;同时进步了复用性。低内聚的毛病:类要做许多不相干的工作,或须要实现大量的工作,导致类难以了解,难以复用,难以保护,常常被改变。如下图,非内聚的类(或模块)蕴含了多个不相干业务的性能,看起来比拟芜杂。对它进行职责拆分后,不同业务的性能放在不同的类(模块),高内聚之后的构造显得非常清晰。 控制器(Controller)定义:把接管或者解决零碎事件音讯的职责调配给一个类(这个类也能够是:子系统,或设施);一个控制器应该解决一类事件,控制器要把实现的性能委托给业务层Service,它只负责协调和管制业务流程。长处:控制器的外围是提供一个对立入口(比方外观模式),防止客户对系统外部进行耦合,很好的保护了职责边界。 多态定义:当相干抉择或行为随类型(类)变动而变动时,用多态操作为行为变动的类型调配职责。长处:多态是面向对象设计的基本操作,它使将来的变动能够通过扩大新的子类解决,合乎开闭准则。 纯虚构(Pure Fabrication)定义:为了反对良好的内聚和低耦合以及复用性,将一组相干职责调配给一个虚构的类(这个类不是问题域中的概念)。比方数据库操作DAO,service,handler等。长处:解耦,以及反对了高内聚和复用性。 间接(Indirection)定义:配职责给两头对象(中介)以协调组件或服务之间的操作,使得它们不间接耦合。长处:实现了类间的隔离和解耦。有一种风趣的说法:“大多数设计问题都能够通过减少一层来解决,如果不行就再加一层。而性能问题则刚好相同,缩小一层就能解决问题。” 受爱护的变动(Protected Variations)定义:找出预计有变动或不稳固的元素,为其创立稳固的“接口”而调配职责。即思考将来变动的扩展性,它是大多数程序设计的根底,是模式的根本动机之一,它使零碎可能适应和隔离变动。与ETC准则统一,与面向对象的开闭准则绝对应。

November 2, 2022 · 1 min · jiezi

关于设计原则:开闭原则OCP的理解与灵活应用

开闭准则可能是 SOLID 中最难了解、最难把握,同时也是最有用的一条准则。 之所以说这条准则难了解,那是因为,“怎么的代码改变才被定义为‘扩大’?怎么的代码改变才被定义为‘批改’?怎么才算满足或违反‘开闭准则’?批改代码就肯定意味着违反‘开闭准则’吗?”等等这些问题,都比拟难了解。之所以说这条准则难把握,那是因为,“如何做到‘对扩大凋谢、批改敞开’?如何在我的项目中灵便地利用‘开闭准则’,以防止在谋求扩展性的同时影响到代码的可读性?”等等这些问题,都比拟难把握。之所以说这条准则最有用,那是因为,扩展性是代码品质最重要的衡量标准之一。在 23 种经典设计模式中,大部分设计模式都是为了解决代码的扩展性问题而存在的,次要听从的设计准则就是开闭准则。开闭准则的英文全称是 Open Closed Principle(OCP)。它的英文形容是:software entities (modules, classes, functions, etc.) should be open for extension , but closed for modification。 用中文具体表述下就是:增加一个新的性能应该是,在已有代码根底上扩大代码(新增模块、类、办法等),而非批改已有代码(批改模块、类、办法等)。 如何了解“对扩大凋谢、对批改敞开”?咱们通过上面的例子来更好的了解“对扩大凋谢、对批改敞开”的含意。 初始示例这是一段 API 接口监控告警的代码。其中, AlertRule 存储告警规定,能够自在设置。Notification 是告警告诉类,反对邮件、短信、微信、手机等多种告诉渠道。NotificationEmergencyLevel 示意告诉的紧急水平,包含 SEVERE(重大)、URGENCY(紧急)、NORMAL(一般)、TRIVIAL(无关紧要),不同的紧急水平对应不同的发送渠道。public class Alert { private AlertRule rule; private Notification notification; public Alert(AlertRule rule, Notification notification) { this.rule = rule; this.notification = notification; } public void check(String api, long requestCount, long errorCount, long durationOfSeconds) { long tps = requestCount / durationOfSeconds; if (tps > rule.getMatchedRule(api).getMaxTps()) { notification.notify(NotificationEmergencyLevel.URGENCY, "..."); } if (errorCount > rule.getMatchedRule(api).getMaxErrorCount()) { notification.notify(NotificationEmergencyLevel.SEVERE, "..."); } }}下面这段代码非常简单,业务逻辑次要集中在 check() 函数中。当接口的 TPS 超过某个事后设置的最大值时,以及当接口申请出错数大于某个最大允许值时,就会触发告警,告诉接口的相干负责人或者团队。 ...

December 7, 2021 · 4 min · jiezi

关于设计原则:开放封闭原则不改代码怎么写新功能

再小的致力,乘以365都很显著前言上一篇文章,咱们讲了一个最根底的设计准则:繁多职责准则。这一讲,咱们来看下一个设计准则:凋谢关闭准则。 作为一名程序员,来了一个需要就要改一次代码,这种形式咱们曾经见怪不怪了,甚至曾经变成了一种下意识的反馈。批改也很容易,只有咱们依照之前的常规如法炮制就好了。 这是一种不费脑子的做法,却随同着长期的挫伤。每人每次都只改了一点点,然而,通过长期积攒,再来一个新的需要,改变量就要很大了。而在这个过程中,每个人都很无辜,因为每个人都只是遵循常规在批改。但后果是,所有人都受到了挫伤,代码越来越难以保护。 既然“批改”会带来这么多问题,那咱们能够不批改吗?凋谢关闭准则就提供了这样的一个新方向。 简介凋谢关闭准则是这样表述的: 软件实体(类、模块、函数)应该对扩大凋谢,对批改关闭。这个说法是 Bertrand Meyer 在其著述《面向对象软件结构》(Object-Oriented Software Construction)中提出来的,它给软件设计提出了一个极高的要求:不批改代码。 或者你想问,不批改代码,那我怎么实现新的需要呢?答案就是靠扩大。用更艰深的话来解释,就是新需要应该用新代码实现。 凋谢关闭准则向咱们形容的是一个后果,就是咱们能够不批改代码而仅凭扩大就实现新性能。然而,这个后果的前提是要在软件外部留好扩大点,而这正是须要咱们去设计的中央。因为每一个扩大点都是一个须要设计的模型。 解释举个例子,如果咱们正在开发一个酒店预订零碎,针对不同的用户,咱们须要计算出不同的房价。比方,普通用户是全价,金卡是 8 折,银卡是 9 折,代码写进去可能是这样的: class HotelService { public double getRoomPrice(final User user, final Room room) { double price = room.getPrice(); if (user.getLevel() == Level.GOLD) { return price * 0.8; } if (user.getLevel() == Level.SILVER) { return price * 0.9; } return price; }}这时,新的需要来了,要减少白金卡会员,给出 75 折的优惠,如法炮制的写法应该是这样的: class HotelService { public double getRoomPrice(final User user, final Room room) { double price = room.getPrice(); if (user.getLevel() == UserLevel.GOLD) { return price * 0.8; } if (user.getLevel() == UserLevel.SILVER) { return price * 0.9; } if (user.getLevel() == UserLevel.PLATINUM) { return price * 0.75; } return price; }}显然,这种做法就是批改代码的做法,每减少一个新的类型就要批改一次代码。然而,一个有各种级别用户的酒店零碎必定不只是房价有区别,提供的服务也可能有区别。可想而知,每减少一个用户级别,咱们要改的代码就铺天盖地。 ...

May 11, 2021 · 1 min · jiezi

关于设计原则:设计模式原则之单一职责原则SRP

人生没有白走的路,每一步都算数前言在面向对象的软件设计中,只有尽量升高各个模块之间的耦合度,能力进步代码的复用率,零碎的可维护性、可扩展性能力进步。面向对象的软件设计中,有23种经典的设计模式,是一套前人代码设计教训的总结,如果把设计模式比作文治招式,那么设计准则就好比是内功心法。罕用的设计准则有七个,本文将具体介绍繁多职责准则。 设计准则简介繁多职责准则:专一升高类的复杂度,实现类要职责繁多;凋谢敞开准则:所有面向对象准则的外围,设计要对扩大开发,对批改敞开;里式替换准则:实现凋谢敞开准则的重要形式之一,设计不要毁坏继承关系;依赖倒置准则:零碎抽象化的具体实现,要求面向接口编程,是面向对象设计的次要实现机制之一;接口隔离准则:要求接口的办法尽量少,接口尽量细化;迪米特法令:升高零碎的耦合度,使一个模块的批改尽量少的影响其余模块,扩大会绝对容易;组合复用准则:在软件设计中,尽量应用组合/聚合而不是继承达到代码复用的目标。这些设计准则并不说咱们肯定要遵循他们来进行设计,而是依据咱们的理论状况去怎么去抉择应用他们,来让咱们的程序做的更加的欠缺。 繁多职责准则就一个类而言,应该仅有一个引起它变动的起因,艰深的说,就是一个类只负责一项职责。此准则的外围就是解耦和加强内聚性。 如果一个类承当的职责过多,就等于把这些职责耦合在一起,一个职责的变动可能会减弱或者克制这个类实现其余职责的能力。这种耦合会导致软弱的设计。 长处: (1)升高类的复杂度; (2)进步类的可读性,进步零碎的可维护性; (3)升高变更引起的危险(升高对其余性能的影响)。 咱们来举一些简略的例子来阐明一下这个繁多职责准则 public class Animal { public void breathe(String animal) { System.out.println(animal + "生存在海洋上"); }}public class Test { public static void main(String[] args) { Animal animal = new Animal(); animal.breathe("牛"); animal.breathe("羊"); }}运行后果: 牛生存在海洋上羊生存在海洋上动物并不是都生存在海洋上的,鱼就是生存在水中的,批改时如果遵循繁多职责准则,须要将Animal类细分为陆生动物类Land,水生动物Water,代码如下:public class Land { public void breathe(String animal) { System.out.println(animal + "生存在海洋上"); }}public class Water { public void breathe(String animal) { System.out.println(animal + "生存在水里"); }}public class Test { public static void main(String[] args) { Land land = new Land(); land.breathe("牛"); land.breathe("马"); Water water = new Water(); water.breathe("鱼"); }}运行后果: ...

May 11, 2021 · 1 min · jiezi

关于设计原则:混合开发TDDDDD和BDD交集的值

目录TDD测试驱动开发 : Test-driven development,即测试驱动开发BDD行为驱动开发 : Behavior-driven development,即行为驱动开发DDD畛域驱动设计 : Domain-drive Design,畛域驱动设计测试驱动开发(TDD)是一种开发软件的过程,其中在编写代码之前先编写测试。一旦实现,开发人员将致力编写足够的代码以通过测试,而后开始重构。 域驱动设计(DDD)是一种将实现与一直倒退的模型分割在一起的开发方法。将我的项目的重点放在外围畛域(常识畛域),背地的逻辑上,并迫使技术和非技术方面之间进行合作以改良模型。行为驱动开发(BDD)是对TDD和DDD的改良,旨在通过放大沟通差距,增进对客户的理解并实现继续沟通来简化开发。简而言之,BDD是将业务需要与代码联合在一起的一种形式,使您可能从业务/最终用户的角度理解零碎的行为。 Hybrid Practice混合实际 TDDTest-driven development,即测试驱动开发。一种开发过程中利用办法。其思维为先依据需要形象接口,先编写测试用例,而后在开始编写开发代码。TDD的本意就是通过测试来推动整个开发的进行。 TDD说白了就是先写一小段性能的测试代码,测试失败后再写实现代码,测试胜利后接着迭代下一个性能。 TDD的长处: 进步性能的可测性测试比拟灵便测试用例覆盖率比拟高毛病: 因为是单元测试代码验证,非技术人员看不懂代码,比拟难验证性能是否贴合需要先写单元测试代码,测试用例须要常常调整,减少了开发人员的工作量和升高了开发效率BDDBehavior-driven development,即行为驱动开发。其目标是激励软件我的项目中的开发者、QA和非技术人员或商业参与者之间的合作。是从用户的需要登程,强调零碎行为。通过用自然语言书写非程序员可读的测试用例扩大了测试驱动开发方法,应用混合了畛域中对立的语言的母语语言来形容他们的代码的目标,让开发者得以把精力集中在代码应该怎么写,而不是技术细节上,而且也最大水平的缩小了将代码编写者的技术语言与商业客户、用户、利益相关者、我的项目管理者等的畛域语言之间来回翻译的代价. 目前支流的BDD测试框架为Cucumber ,反对多种编程语言。 cucumber反对的关键字: feature | "性能" |background | "背景" |scenario | "场景", "剧本" |scenario outline | "场景纲要", "剧本纲要" |examples | "例子" |given | "* ", "如果", "假如", "假设" |when | "* ", "当" |then | "* ", "那么" |and | "* ", "而且", "并且", "同时" |but | "* ", "然而" |given (code) | "如果", "假如", "假设" |when (code) | "当" |then (code) | "那么" |and (code) | "而且", "并且", "同时" |but (code) | "然而" |编程是通过应用以上的关键字来形容利用的性能,使非开发人员能疾速便捷的理解代码的性能。 ...

December 5, 2020 · 1 min · jiezi