一、单一职责原则
- 降低类的复杂性,即一个类应该只负责一项职责。
- 提高类的可读性,可维护性
- 降低变更引起的风险
- 代码逻辑比较简单的情况下,可以在方法级别保持单一职责原则
- 代码示例
/**
* 完全符合单一职责原则
*/
public class Test {
public static void main(String[] args) {
Vehicle vehicle = new Vehicle();
vehicle.run("汽车");
Vehicle1 vehicle1 = new Vehicle1();
vehicle1.run("飞机");
}
}
class Vehicle{
public void run(String vehicle){
System.out.println(vehicle+":在地上跑!");
}
}
class Vehicle1{
public void run(String vehicle){
System.out.println(vehicle+":在天上飞!");
}
}
/**
* 方法级别的单一职责原则
*/
public class Test {
public static void main(String[] args) {
Vehicle vehicle = new Vehicle();
vehicle.run("汽车");
vehicle.runAir("飞机");
}
}
class Vehicle{
public void run(String vehicle){
System.out.println(vehicle+":在地上跑!");
}
public void runAir(String vehicle){
System.out.println(vehicle+":在天上飞!");
}
}
二、接口隔离原则
-
不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小接口上
-
代码示例
/**
* 违反接口隔离原则,代码示例
*/
interface interface1{
public void operation1();
public void operation2();
public void operation3();
}
class B implements interface1{
public void operation1() {
System.out.println("B 实现了 operation1");
}
public void operation2() {
System.out.println("B 实现了 operation2");
}
public void operation3() {
System.out.println("B 实现了 operation3");
}
}
class D implements interface1{
public void operation1() {
System.out.println("D 实现了 operation1");
}
public void operation2() {
System.out.println("D 实现了 operation2");
}
public void operation3() {
System.out.println("D 实现了 operation3");
}
}
/**
* A 类 通过接口 interface1 依赖(使用)B 类,但是只用到 1,2 方法
*/
class A{
public void depend1(interface1 i){
i.operation1();
}
public void depend2(interface1 i){
i.operation2();
}
}
/**
* C 类 通过接口 interface1 依赖(使用)D 类,但是只用到 1,3方法
*/
class C{
public void depend1(interface1 i){
i.operation1();
}
public void depend3(interface1 i){
i.operation3();
}
}
/**
* 遵循接口隔离原则,代码示例
*/
public class Test {
public static void main(String[] args) {
A a = new A();
a.depend1(new B());
a.depend2(new B());
C d = new C();
interface1 ii = new D();
d.depend1(new D());
d.depend3(new D());
}
}
interface interface1{
public void operation1();
}
interface interface2{
public void operation2();
}
interface interface3{
public void operation3();
}
class B implements interface1,interface2{
public void operation1() {
System.out.println("B 实现了 operation1");
}
public void operation2() {
System.out.println("B 实现了 operation2");
}
}
class D implements interface1,interface3{
public void operation1() {
System.out.println("D 实现了 operation1");
}
public void operation3() {
System.out.println("D 实现了 operation3");
}
}
/**
* A 类 通过接口 interface1 依赖(使用)B 类,但是只用到 1,2 方法
*/
class A{
public void depend1(interface1 i){
i.operation1();
}
public void depend2(interface2 i){
i.operation2();
}
}
/**
* C 类 通过接口 interface1 依赖(使用)D 类,但是只用到 1,3方法
*/
class C{
public void depend1(interface1 i){
i.operation1();
}
public void depend3(interface3 i){
i.operation3();
}
}
三、依赖倒转原则
- 高层模块不应该依赖地层模块,二者都应该依赖其抽象
- 抽象不应该依赖细节,细节应该依赖抽象
- 中心思想:面向接口编程
- 依赖倒转原则是基于这样的设计理念,相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。
- 在java中,抽象指的是接口或抽象类,细节就是具体的实现类
- 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成
- 代码实践
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.receive(new Aemail());
person.receive(new Awexin());
}
}
interface Areceiver{
public String getInfo();
}
class Aemail implements Areceiver{
@Override
public String getInfo() {
return "电子邮件信息:hello world";
}
}
class Awexin implements Areceiver{
@Override
public String getInfo() {
return "微信信息:hello world";
}
}
class Person{
public void receive(Areceiver areceiver){
System.out.println(areceiver.getInfo());
}
}
四、里氏替换原则
- 继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障
- 在实际编程中,我们常常会通过重写父类的方法完成新的功能,这样写起来虽然简单,但整个继承体系的复用性会比较差。特别是运行多态比较频繁的时候
- 通用的做法是:原来的父类和子类都继承-一个更通俗的基类,原有的继承关系去掉,
采用依赖,聚合,组合等关系代替. - 使用继承时,遵循里氏替换原则,尽量不要重写父类中的方法
- 代码实践
/**
* 不符合里氏替换原则 代码示例
*/
public class Test {
public static void main(String[] args) {
A a = new A();
System.out.println(a.fun1(7, 3)); // 4
System.out.println(a.fun1(2, 8)); // -6
B b = new B();
System.out.println(b.fun1(7, 3)); // 10
System.out.println(b.fun1(2, 8)); // 10
System.out.println(b.fun2(2, 8)); // 19
}
}
class A {
public int fun1(int a, int b) {
return a - b;
}
}
class B extends A {
@Override
public int fun1(int a, int b) {
return a + b;
}
public int fun2(int a, int b) {
return a + b + 9;
}
}
/**
* 使用 组合 代替继承(使符合里氏替换原则)
*/
class Base {
}
class A extends Base {
public int fun1(int a, int b) {
return a - b;
}
}
class B extends Base {
// 使用 组合 代替继承
private A a = new A();
public int fun1(int a, int b) {
return a + b;
}
public int fun2(int a, int b) {
return a + b + 9;
}
public int fun3(int a, int b) {
return this.a.fun1(a, b);
}
}
五、开闭原则(OCP)
- 开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则
- 一个软件实体如类,模块和函数应该对扩展开放,对修改关闭。用抽象构建框架, .
用实现扩展细节。 - 当软件 需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已
有的代码来实现变化。 - 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。
- 代码实践
public class Test {
public static void main(String[] args) {
DrawShape draw = new DrawShape();
draw.drawShape(new Circle());
draw.drawShape(new Triangle());
}
}
class DrawShape{
public void drawShape(Shape shape){
shape.draw();
}
}
abstract class Shape{
public abstract void draw();
}
class Circle extends Shape{
@Override
public void draw() {
System.out.println("绘制圆形");
}
}
class Triangle extends Shape{
@Override
public void draw() {
System.out.println("绘制三角形");
}
}
六、迪米特法则
- 一个对象应该对其他对象保持最少的了解
- 类与类关系越密切,耦合度越大
- 迪米特法则,又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内.部。对外除了提供的public方法,不对外泄露任何信息
- 代码实践
/**
* 不符合迪米特法则的代码示例
*/
public class Test {
public static void main(String[] args) {
SchoolManage schoolManage = new SchoolManage();
schoolManage.printEmployee(new CollegeManage());
}
}
class SchoolManage {
private List<Employee> employeeList;
SchoolManage() {
employeeList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
employeeList.add(new Employee("学校员工"+i));
}
}
public void printEmployee(CollegeManage collegeManage){
for(Employee e : this.employeeList){
System.out.println(e.getName());
}
System.out.println("---------------------");
for(Employee e : collegeManage.getEmployeeList()){
System.out.println(e.getName());
}
}
}
class CollegeManage {
private List<Employee> employeeList;
CollegeManage() {
employeeList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
employeeList.add(new Employee("学院员工"+i));
}
}
public List<Employee> getEmployeeList() {
return employeeList;
}
}
class Employee {
private String name;
public String getName() {
return name;
}
Employee(String name) {
this.name = name;
}
}
/**
* 将上面的代码简单修改一下,使符合迪米特法则
*/
class SchoolManage {
private List<Employee> employeeList;
SchoolManage() {
employeeList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
employeeList.add(new Employee("学校员工"+i));
}
}
public void printEmployee(CollegeManage collegeManage){
for(Employee e : this.employeeList){
System.out.println(e.getName());
}
System.out.println("--------------------");
collegeManage.printEmployee();
}
}
class CollegeManage {
private List<Employee> employeeList;
CollegeManage() {
employeeList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
employeeList.add(new Employee("学院员工"+i));
}
}
public List<Employee> getEmployeeList() {
return employeeList;
}
public void printEmployee(){
for(Employee e : this.employeeList){
System.out.println(e.getName());
}
}
}
七、合成复用原则
- 尽量使用合成/聚合的方式,而不是使用继承
- 依赖
class A{
public String say(){
return "我是 A ";
}
}
class B{
public void func(A a){
System.out.println(a.say());
}
}
- 聚合
class B{
private A a;
public void setA(A a) {
this.a = a;
}
public void func(){
System.out.println(a.say());
}
}
- 组合
class A{
public String say(){
return "我是 A ";
}
}
class B{
private A a = new A();
public void func(){
System.out.println(this.a.say());
}
}
设计原则核心思想
- 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代
码混在一起。 - 针对接口编程,而不是针对实现编程。
- 为了交互对象之间的松耦合设计而努力