开闭原则
原则
-
对扩展开放,对修改关闭
-
用抽象构建框架,用实现填充细节
优点
提高系统的可维护性和可用性
举例
java
public class Discount {
public double getPrice(int type, double price){
if(type == 1){
return price * 0.9;
}else if(type == 2){
return price * 0.8;
}
// 新加折扣必须改这里
return price;
}
}
java
// 抽象规范
public interface IDiscount {
double calc(double price);
}
// 九折
public class NineDiscount implements IDiscount {
@Override
public double calc(double price) {
return price * 0.9;
}
}
// 八折
public class EightDiscount implements IDiscount {
@Override
public double calc(double price) {
return price * 0.8;
}
}
依赖倒置原则
原则
- 高层模块不应该依赖低层模块,二者都应该依赖其抽象
- 抽象不应该依赖细节,细节应该依赖抽象
- 要针对接口编程
调用方是高层模块
优点
- 减少系统耦合性
- 提高代码可读性和可维护性
- 降低程序修改后引发的风险
举例
java
// 低层具体类
class BMW {
public void run(){
System.out.println("宝马行驶");
}
}
// 高层类依赖具体宝马
class Driver {
public void drive(BMW car){
car.run();
}
}
java
// 抽象:统一行车规范
interface Car {
void run();
}
// 低层具体实现
class BMW implements Car{
@Override
public void run() {
System.out.println("宝马行驶");
}
}
class Benz implements Car{
@Override
public void run() {
System.out.println("奔驰行驶");
}
}
// 高层只依赖抽象,不依赖具体车
class Driver {
public void drive(Car car){
car.run();
}
}
单一职责原则
原则
一个类、接口、方法只负责一项职责
优点
降低类的复杂度
提高代码可读性
提高系统可维护性
降低代码变更引起的风险
举例
java
public class Goods {
private String name;
private double price;
// 展示商品信息
public void showInfo(){
System.out.println("商品:"+name+",单价:"+price);
}
// 计算折扣价
public double countDiscount(double rate){
return price * rate;
}
// 存入数据库
public void saveDb(){
System.out.println("商品数据入库成功");
}
}
java
// 用户业务逻辑
// 实体类:仅存储商品属性
public class Goods {
private String name;
private double price;
// getter、setter
}
// 价格计算类:只负责价格相关运算
public class PriceCalculate {
public double getDiscountPrice(double originPrice, double rate){
return originPrice * rate;
}
}
// 数据存储类:只负责数据库操作
public class GoodsRepository {
public void save(Goods goods){
System.out.println("商品数据入库成功");
}
}
// 信息展示类:只负责页面信息输出
public class GoodsDisplay {
public void printGoods(Goods goods){
System.out.println("商品信息:"+goods.getName()+",原价:"+goods.getPrice());
}
}
接口隔离原则
原则
- 用多个专门的接口
- 不依赖于单一的总接口
- 客户端不应该依赖不需要的接口
优点
- 高内聚,低耦合
- 提升可读性、扩展性和维护性
举例
java
public interface Animal {
void run();
void fly();
void swim();
}
// 陆地动物被迫实现无用方法
class Dog implements Animal{
@Override
public void run() {
System.out.println("狗狗奔跑");
}
@Override
public void fly() {
// 空实现,压根不会飞
}
@Override
public void swim() {
// 多余方法
}
}
java
// 奔跑接口
public interface Runnable {
void run();
}
// 飞行接口
public interface Flyable {
void fly();
}
// 游泳接口
public interface Swimable {
void swim();
}
// 狗只实现自身具备的接口
class Dog implements Runnable,Swimable{
@Override
public void run() {
System.out.println("狗狗奔跑");
}
@Override
public void swim() {
System.out.println("狗狗游泳");
}
}
// 鸟类只实现飞行、奔跑
class Bird implements Runnable,Flyable{
@Override
public void run() {
System.out.println("小鸟走路");
}
@Override
public void fly() {
System.out.println("小鸟飞翔");
}
}
迪米特原则
原则
一个对象应该对其他对象保持最少了解
优点
降低系统耦合度
举例
java
// 老师
class Teacher {
public String name;
}
// 班级
class ClassRoom {
public Teacher teacher;
}
// 学生
class Student {
// 越级访问陌生人内部属性
public void showTeacher(ClassRoom room){
// 连续点调用,知道太多内部细节
System.out.println(room.teacher.name);
}
}
java
class Teacher {
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
class ClassRoom {
private Teacher teacher;
// 对外只暴露方法,不暴露内部对象
public String getTeacherName(){
return teacher.getName();
}
}
class Student {
// 只调用班级提供的方法,不问内部结构
public void showTeacher(ClassRoom room){
System.out.println(room.getTeacherName());
}
}
里氏替换原则
原则
子类可以替换父类,程序行为不会出错
任何使用父类的地方,都能无缝换成子类,逻辑正常运行。
优点
举例
java
// 父类正方形
class Square {
protected int side;
public void setSide(int side){
this.side = side;
}
public int getArea(){
return side * side;
}
}
// 子类长方形,违背替换规则
class Rectangle extends Square{
@Override
public void setSide(int side) {
// 强行篡改逻辑,破坏父类行为
super.side = side / 2;
}
}
// 测试:父类场景放入子类,结果异常
public class Test {
public static void calc(Square square){
square.setSide(4);
System.out.println(square.getArea());
}
public static void main(String[] args) {
calc(new Square()); // 正常16
calc(new Rectangle()); // 结果错乱,替换失败
}
}
java
// 抽象图形
abstract class Shape {
public abstract int getArea();
}
// 正方形
class Square extends Shape{
private int side;
public Square(int side){this.side=side;}
@Override
public int getArea() {
return side*side;
}
}
// 长方形
class Rectangle extends Shape{
private int width,height;
public Rectangle(int w,int h){width=w;height=h;}
@Override
public int getArea() {
return width*height;
}
}
// 任意子类均可替换抽象父类
public class Test{
public static void printArea(Shape shape){
System.out.println(shape.getArea());
}
public static void main(String[] args) {
printArea(new Square(4));
printArea(new Rectangle(2,3));
}
}
合成复用原则
原则
尽量使用组合、聚合而不是继承
优点
- 降低系统耦合度
举例
java
// 发动机父类
class Engine {
public void run() {
System.out.println("引擎运转");
}
}
// 汽车继承发动机,不合理is-a关系
class Car extends Engine {
public void drive() {
run();
}
}
java
// 抽象引擎
interface Engine {
void run();
}
// 汽油引擎
class GasEngine implements Engine{
@Override
public void run() {
System.out.println("汽油引擎运转");
}
}
// 电动引擎
class ElectricEngine implements Engine{
@Override
public void run() {
System.out.println("电动引擎运转");
}
// 汽车组合引擎对象
class Car {
// 组合关系
private Engine engine;
public Car(Engine engine){
this.engine = engine;
}
public void drive(){
engine.run();
}
}