设计原则(单一原则,接口隔离原则,依赖倒转原则...)和设计模式(单例模式,工厂模式...)
一.设计原则
Java的23种设计模式是根据设计原则来的,设计原则实际模式的设计依据.
每一个类用来处理一类事物,尽量使用接口进行方法规范(少使用继承),类与类之间尽量使用引用关系。
-
单一原则:一个类只处理一类事物(分为类单一和方法单一)
A.类单一
B.方法单一 -
接口隔离原则
一个类如果只需要一个接口中的部分方法,请将该接口进行分离.一个接口用来处理一类事物
隔离原则应当这样处理:
将接口 Interface1拆分为独立的几个接口(这里我们拆分成 3 个接口),类 A 和类 C 分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则( 每一个类所依赖的接口为最小接口,最小接口就是接口中的规定的方法不要有多余的)
- 依赖倒转原则
依赖倒转原则是指:
(1)高层模块不应该依赖低层模块,二者都应该依赖其抽象
(2)抽象不应该依赖细节,细节应该依赖抽象
(3)依赖倒转(倒置)的中心思想是面向接口编程,使用多态(父类引用指向子类对象)
(4)依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在java 中,抽象指的是接口或抽象类,细节就是具体的实现类
(5)使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成
- 里氏替换原则
- 在继承的时候,子类无意间重写父类的方法。如果我们对父类中的方法进行了修改,有可能会影响到子类的代码。
- 继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障。
- 在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法
- 里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖 来解决问题。
- 开闭原则
- 对扩展开放,对修改关闭 .是对父类开放扩展,对子类关闭修改(不要试图修改子类的方式来修改父类)
- 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
- 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。
- 迪米特法则:对外暴露越少越好,类与类之间尽量找直接关系。
(1)迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的 public 方法,不对外泄露任何信息
(2)迪米特法则还有个更简单的定义:只与直接的朋友通信
- 合成复用原则
- 就是尽量使用类与类的引用关系来进行方法的调用
例一
例二
合成复用其实就是做类与类的引用
二.设计模式
设计模式是根据设计原则结合实际开发中的方式,进行总结出来的一套编程模式。 根据需求不同分类 :
创建型模式: 主要是用来实例化对象用的 (单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式)
结构型模式: 对象或类的调用(适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式)
行为型模式: 不同类之间的相互处理(模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter 模式)、状态模式、策略模式、职责链模式(责任链模式))
- 单例模式
-
通过类new一次就会得到一个实例对象,多次new得到是不同的对象。
-
如果需要得到同一个对象:单例模式是通过改变获取java对象的方式得到同一个java对象 (不要使用new的方式来得到java对象) 使用方
-
为了不让使用方直接使用:将提供方的构造方法私有化
//构造方法
private Student(String name){
this.name=name;
}
private Student(){
}
操作是对构造方法私有化,封装的思想,暴露一个得到java的public方法
单例模式就是为了得到相同的对象,不使用new的方式来得到对象(使用方),在本类中将构造方法进行私有化,提供一个返回一个java对象的public方法。那个使用方要一个java对象 就使用我的公共方法得到。
(1)饿汉模式: 管你有没有 我都要创建
-
使用静态属性来统一java对象
-
使用静态代码块的方式来得到对象
饿汉模式会导致内存浪费,没有要实例化对象的时候,对象都已经被实例化出来了 。
(2) 懒汉模式
得到对象的时候,第一次进来,如果对象没有被实例化,我们就实例化一个,如果已经实例化了,就直接拿来用就可以了。
- 工厂模式
- 所谓的工厂就是一个第三方类,工具类。
测试类–>工厂–>Student
(1) 普通工厂
(2)静态工厂
就是我只需要通过工厂的流水线得到我要的实例化对象,我并不需要工厂对象。
(3) 抽象工厂
- 该工厂是一个抽象的, 该工厂自己不会干,找两个实际工厂来做(多态思想 )
- 抽象工厂自己并不会生产,拥有的是抽象方法,实际根据需要使用多态得到已知实现子类工厂。 实际调用的是非抽象工厂的方法来创建手机对象。
可以将工厂升级为接口来实现
作用:对代码的修改维护降低
- 代理工厂
- 使用第三方代理对象类调用要代理的对象,执行代理对象的方法其实就是执行被代理对象的方法。(代理对象,被代理对象)
- 作用:是用来对被代理对象的方法进行增强
- 手动编写的代理程序 、 JDK动态代理、CGLib动态代理
代理模式注意以下几点:
- 代理对象的方法与被代理对象的方法声明的时候一致(返回值、参数、方法名)
- 实际使用的时候调用的是代理对象的方法,其实最终调用的就是被代理对象的方法
- 在代理对象中,调用被代理对象的方法时候对方法进行增强(扩展)不能减弱。
- 代理在日常开发中的主要功能:日志记录,异常信息输出
- 五种增强方式:前置,后置,环绕,最终,异常
- 建造者模式(Service三层架构: 控制层,业务层,实际操作层)
将实例化对象的方式分为了不同的操作
(1)建造者模式的四个角色
-
Product(产品角色): 一个具体的产品对象。
-
Builder(抽象建造者): 创建一个 Product 对象的各个部件指定的 接口/抽象类。
-
ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。
-
Director(指挥者): 构建一个使用 Builder 接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
-
Javabean实体类:不应该有该类的操作
-
建造者:操作该Javabean的接口或者抽象类(方法只有定义没有具体执行 )
-
具体建造者(具体的执行者):操作类/接口 实现类
-
指挥者:Service 控制层,业务层,实际操作层
-
主启动类:不与核心对象有直接关系 ,通过指挥者来建立联系
eg:
学生管理系统 数组
StudentBean 实体类
StudentDao 接口
StudentDaoImp 实际操作者
StudentService 指挥者(调用实际操作做)
StudentTest 主程序 (测试类)
Student类(实体类)
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
StudentDao类(接口)
public interface StudentDao {
// 查询所有 去数组中查
Student[] getAllStudent(Student[] students);
}
StudentDaoImp类
public class StudentDaoImp implements StudentDao {
@Override
public Student[] getAllStudent(Student[] students) {
Student[] stus=new Student[students.length];
int index=0;
// 查询有效数据
for (Student student : students) {
if(student!=null) {
stus[index]=student;
System.out.println(student);// 输出语句
index++;
}
}
return stus;
}
}
StudentService类
public class StudentService {
// 引用接口,合成复用原则
private StudentDao studentDao; //引用
//构造方法
public StudentService() {
super();
// TODO Auto-generated constructor stub
}
public StudentService(StudentDao studentDao) {
super();
this.studentDao = studentDao;
}
// 业务层调用实际操作层
public Student[] getAllStudent(Student[] students) {
// 实际是使用实际操作类来查询
Student[] allStudent = studentDao.getAllStudent(students);
return allStudent;
}
}
StudentTest类(测试类)
public class StudentTest {
public static void main(String[] args) {
// 容器
Student [] students=new Student[3];
students[0]=new Student("张三",20);
students[1]=new Student("张三001",21);
students[2]=new Student("张三002",22);
// 实例化 业务层 需要一个接口对象,使用多态用已知实现子类来做
StudentService ss= new StudentService(new StudentDaoImp());
// 调用 业务层代码
ss.getAllStudent(students);
}
}
- 建造者模式必须遵守四个对象 实体、接口、实现类、业务类。
- 代码的扩展和维护方便,接口清楚,对于操作的约束性很高。
- 适配器模式:将不符合要求的东西转为符合要求的东西
(1)适配器模式基本介绍
适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表 示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作,其别名为包装器(Wrapper)
适配器模式属于结构型模式
主要分为三类:类适配器模式、对象适配器模式、接口适配器模式
(2)适配器模式工作原理
适配器模式:将一个类的接口转换成另一种接口,让原本接口不兼容的类可以兼容
从用户的角度看不到被适配者,是解耦的
用户调用适配器转化出来的目标接口方法,适配器再调用被适配者的相关接口方法
用户收到反馈结果,感觉只是和目标接口交互
a.类适配器模式
Dian220类
public class Dian220 {
public int outV() {
return 200;
}
}
Dian5类
public class Dian5 {
// 充电
public void chongdian() {
Dian220 d220=new Dian220();
int outV = d220.outV();
// 转换
if(outV==5) {
System.out.println("直接充电");
}else {
// 对现有电压进行转换
outV=5;
if(outV==5) {
System.out.println("转换后 可以充电了");
}else {
System.out.println("电压不对不能充电");
}
}
}
}
测试类
public class ShiTest {
@Test
void test() {
Dian5 d5=new Dian5();
d5.chongdian();
}
}
b.对象适配器
(1) 思路和类的适配器模式相同,只是将 Adapter 类作修改,不是继承 src 类,而是持有 src 类的实例,以解决兼容性的问题。 即:持有 src 类,实现 dst 类接口,完成 src->dst 的适配
(2)根据“合成复用原则”,在系统中尽量使用关联关系(聚合)来替代继承关系。
(3)对象适配器模式是适配器模式常用的一种
- 使用合成复用原则,将继承去掉,使用类与类的引用。
- 一个类无法直接使用另外一个类提供的方法,需要一个第三方类来我们将原本不合适的方法进行转换,达到正常使用的效果
本文地址:https://blog.csdn.net/serendipity_xr/article/details/109583665
下一篇: MySQL数据库——过滤数据