设计模式:设计原则

程序设计的原则

    • 1. 单一设计原则
    • 2. 接口隔离原则
    • 3. 依赖倒转
    • 4. 里氏替换原则
    • 5. 开闭原则
    • 6. 迪米特原则
    • 7. 合成复用

1. 单一设计原则

每一个类只负责做自己的的功能。不能跨越到其它类。

  • 不合理
package top.bitqian.principle.single_responsibility;/*** @author echo lovely* @since 2021/4/10 16:45* @description* <p>*     单一设计原则:*     <li>降低类的复杂度, 一个类只维护一项职责</li>*     <li>提高类的可读性, 可维护性</li>*     <li>降低变更引起的风险</li>*     <li>*     usual, 一般遵守单一设计原则, *     只有逻辑足够简单, 才能<label>代码级别</label>违反单一设计原则, *     如果方法足够少, 可以在方法级别保持单一职责原则。*     </li>* </p>*/public class SingleResponsibility1 {public static void main(String[] args) {Vehicle vehicle = new Vehicle();vehicle.run("火车");vehicle.run("汽车");// 飞机在陆地上不合理..vehicle.run("飞机");}/*** vehicle, there is...*/static class Vehicle {public void run(String vehicle) {System.out.println(vehicle + " 在陆地上跑.....");}}
}
  • 基于类级别
package top.bitqian.principle.single_responsibility;/*** @author echo lovely* @date 2021/4/10 16:53* @description <P>*     拆分, 将交通工具拆分为多个类, 每个交通工具做各自的事情*     优点:如果每个大职责下, 有很多小的功能, 细节的地方, 比如轮船启动前, 要排水, 飞机要检修... 可以拆*     缺点:当功能少, 只考虑到运行时, 下面的设计显得冗余。* </P>*/public class SingleResponsibility2 {public static void main(String[] args) {// 分为三个类, 各司其职new RoadVehicle().run("汽车");new AirVehicle().run("飞机");new WaterVehicle().run("轮船");}static class RoadVehicle {public void run(String roadVehicle) {System.out.println(roadVehicle + "在路上运行");}}static class AirVehicle {public void run(String airVehicle) {System.out.println(airVehicle + "在天上运行");}}static class WaterVehicle {public void run(String waterVehicle) {System.out.println(waterVehicle + "在水上运行");}}}
  • 基于方法级别
package top.bitqian.principle.single_responsibility;/*** @author echo lovely* @date 2021/4/10 17:00* @description* <p>*     方法级别 进行单一设计原则* </p>*/public class SingleResponsibility3 {public static void main(String[] args) {Vehicle vehicle = new Vehicle();vehicle.airRun("飞机");vehicle.roadRun("汽车");vehicle.waterRun("轮船");}static class Vehicle {public void roadRun(String name) {System.out.println(name + "在陆地上run");}public void airRun(String name) {System.out.println(name + "在天空上run");}public void waterRun(String name) {System.out.println(name + "在水上run");}}}

2. 接口隔离原则

每一个接口只负责一件事,记住,接口是规范, 规定某种具体的行为。具体的一件事。
每一接口尽可能只负责一项功能。这里演示接口拆分,将接口拆成多个接口。
  • 需求,错误的设计
package top.bitqian.principle.segregation;/*** @author echo lovely* @date 2021/4/10 17:46* @description* <p>*     接口隔离原则, 将接口拆分**     业务:*     A, B 实现MyInterface**     C 通过 MyInterface依赖(使用)A, operation1, 2, 3三个方法*     D 通过 MyInterface依赖B, 使用 operation1, 4, 5三个方法*** </p>*/public class Segregation1 {public static void main(String[] args) {C c = new C();// c中依赖 A中, operation1,2,3 方法c.dependency1(new A());c.dependency2(new A());c.dependency3(new A());// d依赖B operation1,4.,5 方法D d = new D();d.dependencyD1(new B());d.dependencyD2(new B());d.dependencyD3(new B());/*分析: 现在, C 依赖A (1.2.3), D 依赖B (1.4.5),而A中的4,5方法, B中的2,3方法显得多余..*/}/*** 定义接口, 5个方法 操作*/interface MyInterface {void operation1();void operation2();void operation3();void operation4();void operation5();}/*** A 实现 MyInterface*/static class A implements MyInterface {@Overridepublic void operation1() {System.out.println("A operation1");}@Overridepublic void operation2() {System.out.println("A operation2");}@Overridepublic void operation3() {System.out.println("A operation3");}@Overridepublic void operation4() {System.out.println("A operation4");}@Overridepublic void operation5() {System.out.println("A operation5");}}/*** B 实现 MyInterface*/static class B implements MyInterface {@Overridepublic void operation1() {System.out.println("B operation1");}@Overridepublic void operation2() {System.out.println("B operation2");}@Overridepublic void operation3() {System.out.println("B operation3");}@Overridepublic void operation4() {System.out.println("B operation4");}@Overridepublic void operation5() {System.out.println("B operation5");}}// C, D类 通过MyInterface 依赖 A, B/*** 依赖A类 1,2,3*/static class C {public void dependency1(MyInterface i) {i.operation1();}public void dependency2(MyInterface i) {i.operation2();}public void dependency3(MyInterface i) {i.operation3();}}/*** 依赖D 1,4,5*/static class D {public void dependencyD1(MyInterface i) {i.operation1();}public void dependencyD2(MyInterface i) {i.operation4();}public void dependencyD3(MyInterface i) {i.operation5();}}}
上面的接口只定义了一个接口MyInterface, 而这个接口中,并不是子类都需要使用的,
所以可以将这个接口拆分多个接口。让子类选择性的实现多个接口中的某几个。
  • 解决
package top.bitqian.principle.segregation.aprove;/*** @author echo lovely* @date 2021/4/10 18:30* @description* <p>*     隔离方案2, 拆分接口*     <a href="top.bitqian.principle.segregation.Segregation1">pls see</a>* </p>* @see top.bitqian.principle.segregation.Segregation1*/public class Segregation2 {public static void main(String[] args) {C c = new C();c.dependency1(new A());c.dependency2(new A());c.dependency3(new A());D d = new D();d.dependencyD1(new B());d.dependencyD2(new B());d.dependencyD3(new B());}/*将5个方法的接口, 拆分为3个部分, 让类来实现*/interface MyInterface1 {void operation1();}interface MyInterface2 {void operation2();void operation3();}interface MyInterface3 {void operation4();void operation5();}/*** A 实现1,2,3方法*/static class A implements MyInterface1, MyInterface2 {@Overridepublic void operation1() {System.out.println("A impl operation1");}@Overridepublic void operation2() {System.out.println("A impl operation2");}@Overridepublic void operation3() {System.out.println("A impl operation3");}}/*** B实现了1,4,5 方法*/static class B implements MyInterface1, MyInterface3 {@Overridepublic void operation1() {System.out.println("B impl operation1");}@Overridepublic void operation4() {System.out.println("B impl operation4");}@Overridepublic void operation5() {System.out.println("B impl operation5");}}/*** C 通过拆分的MyInterface1 MyInterface2两个接口 间接的依赖了A类*/static class C {public void dependency1(MyInterface1 i1) {i1.operation1();}public void dependency2(MyInterface2 i2) {i2.operation2();}public void dependency3(MyInterface2 i2) {i2.operation3();}}/*** D 通过拆分的 MyInterface1 MyInterface3两个接口 依赖了B*/static class D {public void dependencyD1(MyInterface1 i1) {i1.operation1();}public void dependencyD2(MyInterface3 i3) {i3.operation4();}public void dependencyD3(MyInterface3 i3) {i3.operation5();}}}

3. 依赖倒转

面向接口编程

  • 需求描述
package top.bitqian.principle.dependency_inversion;/*** @author echo lovely* @date 2021/4/11 10:28* @description* <P>*     依赖倒转原则:*     1. 面向接口编程*      <ul>*         <li>接口作为参数传递</li>*         <li>构造方法传递接口</li>*         <li>setter传递接口参数</li>*      </ul>*     2. 接口, 抽象类的细节越少越好, 细节应该交给子类*     3. 注意点:*     <ul>*         <li>模块尽量使用抽象类 或者接口, (两者都实现), more stable</li>*         <li>变量的声明类型尽量是接口或者抽象类, 在变量的使用和实际对象之间, 存在缓冲层, 有利于程序扩展和优化.</li>*         <li>继承遵循里氏替换原则</li>*     </ul>* </P>*/public class DemoInversion1 {public static void main(String[] args) {// somebody get a msg from email..// but he just got a email..new Person().receive(new Email());}static class Email {String getInfo() {return "from email: hello, adorable";}}static class Person {void receive(Email email) {String msg = email.getInfo();System.out.println(msg);}}}
  • 定义接口,使用接口作为依赖
package top.bitqian.principle.dependency_inversion.improve;/*** @author echo lovely* @date 2021/4/11 10:41* @description <p>*     模仿person接收消息* </p>*/public class DemoInversion2 {public static void main(String[] args) {/** 依赖倒转 like 多态*/Person p = new Person();p.receive(new Email());p.receive(new YouTelegram());}/*** 获取消息接口*/interface IReceiver {String getInfo();}static class Email implements IReceiver {@Overridepublic String getInfo() {return "from email: hello, adorable";}}static class YouTelegram implements IReceiver {@Overridepublic String getInfo() {return "from t.me: hello, bitQian";}}/*** person 接收到消息*/static class Person {void receive(IReceiver receiver) {String info = receiver.getInfo();System.out.println(info);}}}

上面的依赖是通过参数传递, 还可以通过setter方法, 构造器。

4. 里氏替换原则

继承需要遵循这个原则。

1. 如果父类是普通的类(非抽象,接口) 不要改写父的方法实现。
2. 如果重载父类实现的方法, 子类的方法参数必须比父类的大
(父是ArrayList子则是List或者Collection或者Iterator)
3. 重载, 返回要比父的小
4. 父是abstract, 则必须实现父的抽象。子类可以有自己的方法。
package top.bitqian.principle.liskov;import java.util.HashMap;
import java.util.Map;/*** @author echo lovely* @date 2021/4/12 20:34* @description* <p>*     继承缺点:*     <p>*       继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法。*       降低了代码的灵活性。因为继承时,父类会对子类有一种约束。*       增强了耦合性。当需要对父类的代码进行修改时,必须考虑到对子类产生的影响。*       有时修改了一点点代码都有可能需要对打断程序进行重构。*     </p>*     里氏替换原则: <strong>只要有父类出现的地方,都可以用子类来替代</strong>*     <li>*         pls see <a href="https://www.jianshu.com/p/cf9f3c7c0df5">extends..</a>*     </li>*     <li>*        case1: 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。*        case2: 子类中可以增加自己特有的方法。*        case3: 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。(形参更大)*        case4: 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。(返回更小)*     </li>* </p>*/public class Liskov1 {public static void main(String[] args) {A a = new A();System.out.println("3-2=" + a.fun1(3, 2));System.out.println("----------");B b = new B();System.out.println("3-2=" + b.fun1(3, 2));// 执行了父类方法, 但是hello并未被重写... 可能导致程序的混乱..Map<?, ?> map = new HashMap<>();Case3.A a1 = new Case3.A();a1.hello(map);// 执行了子类方法Case3.B b1 = new Case3.B();b1.hello(new HashMap<>());// {}父类的方法b1.hello(map);}static class A {// but that's sub.. 编程时有可能写错int fun1(int a, int b) {return a - b;}}/*** 子类不可实现父类已经实现的方法*/static class B extends A {// add, 子类不要覆盖父类已经实现的方法..@Overrideint fun1(int a, int b) {return a + b;}}static class Case3 {static class A {void hello(Map<?, ?> map) {System.out.println(map + "父类的方法");}}static class B extends Case3.A {// 重载了...void hello(HashMap<?, ?> map) {System.out.println(map + "子类的方法");}}}/*** 子类的返回必须比父类小*/static class Case4 {static abstract class A {abstract Map<?, ?> fun1();}static class B extends Case4.A {/*** 返回值类型必须比父类的小, 否则编译器报错* @return null*/HashMap<?, ?> fun1() {return null;}}}}
  • 使用抽象, 抽取, 解决
package top.bitqian.principle.liskov.improve;/*** @author echo lovely* @date 2021/4/12 21:17* @description <p>*     更好的解决方案* </p>*/public class Liskov2 {public static void main(String[] args) {A a = new A();System.out.println("3-2=" + a.fun1(3, 2));System.out.println("----------");B b = new B();System.out.println("3+2=" + b.fun1(3, 2));System.out.println("3-2=" + b.fun2(3, 2));}static abstract class Base {}static class A extends Base {public int fun1(int a, int b) {return a - b;}}/*** 通过继承基类 解耦...*/static class B extends Base {// 依赖 Aprivate final A myA = new A();// B与A 无关 不可能认为是重写 add..int fun1(int a, int b) {return a + b;}int fun2(int a, int b) {return this.myA.fun1(a, b);}}}

5. 开闭原则

  • 画图demo
package top.bitqian.principle.open_close;/*** @author echo lovely* @date 2021/4/17 10:04* @description* <p>*     ocp 开闭原则...*     <li>提供方可扩展, 调用方关闭, 调用方不修改</li>* </p>*/public class Ocp {public static void main(String[] args) {new GraphicEditor(new Circle());new GraphicEditor(new Triangle());}// 调用方static class GraphicEditor {private final Shape shape;GraphicEditor(Shape shape) {this.shape = shape;this.drawCircle();}void drawCircle() {// fixme: 如果我有很多形状, 这里要加很多判断if (shape.type == 1) {System.out.println("draw circle...");}if (shape.type == 2) {System.out.println("draw Triangle...");}}}// 提供方static class Shape {Integer type;}static class Circle extends Shape {Circle() {super.type = 1;}}static class Triangle extends Shape {Triangle() {super.type = 2;}}}
  • 通过依赖抽象解决
package top.bitqian.principle.open_close.improve;/*** @author echo lovely* @date 2021/4/17 10:13* @description* <p>*     开闭原则实现demo* </p>*/public class Ocp1 {public static void main(String[] args) {new GraphicEditor(new Circle()).drawShape();new GraphicEditor(new Triangle()).drawShape();}// 调用方static class GraphicEditor {private final Shape shape;GraphicEditor(Shape shape) {this.shape = shape;}/*** draw sth...*/void drawShape() {// 这里可以不用改变了, 只要改变子类的实现细节, 就可画出不同的形状..shape.shapeDetail();}}// 提供方static abstract class Shape {Integer type;/*** 提供抽象*/abstract void shapeDetail();}static class Circle extends Shape {Circle() {super.type = 1;}@Overridevoid shapeDetail() {System.out.println("draw circle...");}}static class Triangle extends Shape {Triangle() {super.type = 2;}@Overridevoid shapeDetail() {System.out.println("draw triangle...");}}}

6. 迪米特原则

抽取, 低耦合, 封装,保持在成员变量,参数,返回值直接的耦合。
不要在方法体里面出现默认类。(别在方法体里面new陌生对象。)
package top.bitqian.principle.demeter;import lombok.Data;import java.util.ArrayList;
import java.util.List;/*** @author echo lovely* @date 2021/4/17 11:27* @description <p>* 迪米特原则:* 最小知道原则, 对依赖的类知道的越少越好, 依赖类只提供public方法给被依赖类访问* 通过方法参数, 方法返回值, 成员变量产生耦合* </p>*/public class Demeter1 {public static void main(String[] args) {//创建了一个 SchoolManager 对象SchoolManager schoolManager = new SchoolManager();//输出学院的员工 id 和 学校总部的员工信息schoolManager.printAllEmployee(new CollegeManager());}//学校总部员工类@Datastatic class Employee {private String id;}//学院的员工类@Datastatic class CollegeEmployee {private String id;}//管理学院员工的管理类static class CollegeManager {//返回学院的所有员工public List<CollegeEmployee> getAllEmployee() {List<CollegeEmployee> list = new ArrayList<>();for (int i = 0; i < 10; i++) { //这里我们增加了 10 个员工到 listCollegeEmployee emp = new CollegeEmployee();emp.setId("学院员工 id= " + i);list.add(emp);}return list;}}//学校管理类//分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager//CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则static class SchoolManager {//返回学校总部的员工public List<Employee> getAllEmployee() {List<Employee> list = new ArrayList<>();for (int i = 0; i < 5; i++) { //这里我们增加了 5 个员工到 listEmployee emp = new Employee();emp.setId("学校总部员工 id= " + i);list.add(emp);}return list;}//该方法完成输出学校总部和学院员工信息(id)void printAllEmployee(CollegeManager sub) {//分析问题//1. 这 里 的 CollegeEmployee 不是 SchoolManager 的直接朋友//2. CollegeEmployee 是以局部变量方式出现在 SchoolManager//3. 违反了迪米特法则// fixeme: 可将下面的这段代码抽取到CollegeManager//获取到学院员工List<CollegeEmployee> list1 = sub.getAllEmployee();System.out.println("------------学院员工------------");for (CollegeEmployee e : list1) {System.out.println(e.getId());}//获取到学校总部员工List<Employee> list2 = this.getAllEmployee();System.out.println("------------学校总部员工------------");for (Employee e : list2) {System.out.println(e.getId());}}}}

7. 合成复用

package top.bitqian.principle.composite;/** @author echo lovely* @date 2021/4/17 15:38* @description* <p>* 合成复用原则: 如果两个类没有多大关系, 不要使用继承关系。*      1. 使用依赖关系, 依赖的类作为方法参数.*      2. 使用聚合关系作为成员变量, 使用构造器, 或者setter方法初始化.*      3. 使用复用关系, 初始化的成员变量.* </p>*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/420340.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android数据库LitePal的存储操作

本文属于转载&#xff0c;在此声明&#xff0c;出处&#xff1a;http://blog.csdn.net/guolin_blog/article/details/38556989 并且感谢guolin分享了这么精彩的博文。以下正文&#xff1a; 经过前面几篇文章的学习&#xff0c;我们已经把LitePal的表管理模块的功能都很好地掌握…

程控电源测试微安电流模式_无缝隙源和负载的切换:双向程控电源的一大门槛...

目前采用电池供电的直流无刷电机驱动的设备越来越多&#xff0c;从电动工具&#xff0c;无人机、机器人、再到电动汽车等。然而电机驱动器和电池的管理始终是研发工程师不得不面对的一道难题。电动机利用的是“电生磁”原理&#xff0c;把电能转换成机械能。但制动&#xff0c;…

前端学习(1324):anysc关键字

//只能出现再异步函数中 暂停异步函数得执行 async function fn() {throw 发生勒一些错误;return 123; } //console.log(fn()) fn().then(function(data) {console.log(data); }).catch(function(err) {console.log(err); }) 运行结果

Pacman主题下给Hexo增加简历类型

原文 http://blog.zanlabs.com/2015/01/02/add-resume-type-to-hexo-under-pacman-theme/ 背景 虽然暂时不找工作&#xff0c;但是想着简历也是个向别人推销自己的好东西。然后也想着折腾点新的东西&#xff0c;如此&#xff0c;这般&#xff0c;便想着研究起写个简历了。形式不…

屏幕输出语句_C语言快速入门——表达式与语句

表达式表达式是由运算符和操作数组合构造成。最简单的表达式是一个单独的操作数&#xff0c;以此作为基础&#xff0c;结合语言自身支持的操作符&#xff0c;就可以建立复杂的表达式。下面是一些表达式&#xff1a;从这里可以看到&#xff0c;操作数可以是数据常量(4&#xff0…

前端学习(1325):await关键字

async function p1() {return p1; } async function p2() {return p2; } async function p3() {return p3; } async function run() {let r1 await p1();let r2 await p2();let r3 await p3();console.log(r1);console.log(r2);console.log(r3);} run(); 运行结果

接口测试客户端的搭建

一. 引言 随着公司项目整体架构由原来的多渠道各自为战&#xff0c;向着建立统一的服务端应用&#xff0c;从而为各渠道提供服务调用的转变&#xff0c;服务端应用接口测试成了我们日常工作中的重要任务之一。经过半年的摸索和项目实战&#xff0c;我们已经掌握了一套接口测试的…

python对excel数据求和_96、python操作excel求和

这里介绍如何用python来自动完成我们的excel工作。本文的目的是展示一些常见的Excel任务&#xff0c;以及如何在python pandas中执行类似的任务。例子微不足道&#xff0c;但重要的是通过这个例子来循序渐进的介绍pandas简单到复杂的功能。展示pandas如何利用Python的完整的模块…

前端学习(1327):node全局对象global

global.console.log(我是歌谣); global.setTimeout(function() {console.log(123); }, 2000) 运行结果

4字节 经纬度_java 获取本机经纬度

package com.smm.web.mtower.util;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.net.URL;/*** Created by zhenghao on 2016/6/24.* 当前位置处理工具*/public class LocationUtil {/*…

C#秘密武器之反射——基础篇

先来一段有用的反射代码 namespace Calculator { public interface Iwel { String Print(); } } namespace Calculator { public class Arithmetic:Iwel { /// <summary> /// 没有带参数的构造函数 /// </summary> public Arithmetic() {} public Arithmetic(i…

python社区版可以用库么_应用Python,你不但能够得到出色的小区适用和普遍的库集...

哪样计算机语言最好是&#xff1f;这个问题很有可能始终不容易找答案。萝卜青菜&#xff0c;各有所好&#xff0c;AI技术工程师和生物学家能够依据新项目必须&#xff0c;从诸多计算机语言中挑选最合适自身的。选Python還是选Java?2020年&#xff0c;顶级程序猿最应当把握的7种…

Python3 etree, requests库抓取bt

bt种子抓取1. 抓取你想要的数据2. 爬取bt种子3. 抓取磁力链迷上了追番.. . bt种子xunlei来解决。 推荐一个网站https://mikanani.me。可以搜索你想要的动漫… 以bt的形式下载&#xff0c;或者复制磁力链。 1. 抓取你想要的数据 需要了解requests, etree库&#xff0c;etree用…

ecshop各个文件夹作用

Images文件夹&#xff1a;这个文件夹下有子文件夹&#xff0c;在这些子文件夹下面存放着当前网站商品的原始图片和缩略图。这些子文件夹命名有规律的&#xff0c;它们的文件名是它们目录下商品加入 的年月份。也就是说在同一个月份加入的商品&#xff0c;它们的图片是在同一个文…

unity2018关联不到vs_现实VS真爱:远嫁的幸福和悲哀

陆拾一 LUSHIYI《现实VS真爱&#xff1a;远嫁的幸福和悲哀》Part.1你有过远嫁的犹豫或者经历吗&#xff1f;关于这个话题&#xff0c;我从未写过。今天借着一封读者的来信&#xff0c;与大家聊一聊。拾一&#xff0c;你好。我跟男朋友在一起两年了&#xff0c;现在到了谈婚论嫁…

dubbo使用nacos作为注册中心

spring-cloud nacos dubbodubbo接口服务提供者消费者&#xff0c;要订阅对应的服务&#xff0c;订阅提供者使用openFeign以http为协议进行rest调用。而dubbo是tcpport&#xff0c;使用tcp协议的。 版本说明 dubbo : 2.7.8 spring-cloud-alibaba: 2.1.4.RELEASE spring-cloud:…

vim下php文件中自动缩排html代码

问题&#xff1a;vim下怎样在php文件中通过 命令自动缩排html代码&#xff1f;解决&#xff1a;1、先说下html自动缩排 我的vim是7.4版本&#xff0c;已经包含了html.vim之类的缩排插件&#xff0c;但是缩排的时候<body> <head> 没有进行缩排 在.vimrc中加入如下代…