java-软件设计原则
一、开闭原则
对扩展开放,对修改关闭。在程序需要扩展时,不能去修改原有的代码,实现热插拔的效果。为了使程序更好的进行维护和升级。
想要达到这样的效果,我们需要使用接口或者抽象类。
因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。
定义一个抽象类(AbstractSkin),而每个具体的皮肤(DefaultSpecificSkin和HeimaSpecificSkin)是其子类。用户窗体可以根据需要选择或者增加新的主题,而不需要修改原代码,所以它是满足开闭原则的。
举例:
定义一个抽象类AbstractSkin :
java
public abstract class AbstractSkin {
//显示的方法
public abstract void display();
}
DefaultSkin 子类继承AbstractSkin 抽象类:
java
public class DefaultSkin extends AbstractSkin{
public void display() {
System.out.println("默认皮肤");
}
}
定义一个HeimaSkin类,继承AbstractSkin抽象类
java
public class HeimaSkin extends AbstractSkin{
public void display() {
System.out.println("黑马皮肤");
}
}
定义输入法类:可以根据setSkin()方法中传入的不同皮肤类型,实现不同的效果。
java
public class SougouInput {
private AbstractSkin skin;
public void setSkin(AbstractSkin skin) {
this.skin = skin;
}
public void display() {
skin.display();
}
}
测试类:创建SougouInput对象,可以创建不同的皮肤对象,调用setSkin()方法,将皮肤对象set到input对象中,实现不同皮肤显示。
java
public class Client {
public static void main(String[] args){
//1.创建搜狗输入法对象
SougouInput input = new SougouInput();
//2.创建皮肤对象
//DefaultSkin skin = new DefaultSkin();
HeimaSkin skin = new HeimaSkin();
//3.将皮肤设置到输入法中
input.setSkin(skin);
//4.显示皮肤
input.display();
}
}
二、里氏代换原则
子类可以实现扩展父类的功能,但不能改变父类原本的功能。
比如:
在数学领域里,正方形毫无疑问是长方形,它是一个长宽相等的长方形。所以,我们开发的一个与几何图形相关的软件系统,就可以顺理成章的让正方形继承自长方形。
代码如下:
java
/**
* 长方形类
*/
public class Rectangle {
private double length;
private double width;
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
}
/**
* 正方形类
*/
public class Square extends Rectangle{
@Override
public void setLength(double length) {
super.setLength(length);
super.setWidth(length);
}
@Override
public void setWidth(double width) {
super.setWidth(width);
super.setLength(width);
}
}
正方形类继承了长方形类,重写了setWidth()方法和setLength()方法。
这违反了里氏代换原则。正确写法:
java
/**
* 四边形接口
*/
public interface Quadrilateral {
//获取长
double getLength();
//获取宽
double getWidth();
}
* 长方形类
*/
public class Rectangle implements Quadrilateral{
private double length;
private double width;
public void setLength(double length) {
this.length = length;
}
public void setWidth(double width) {
this.width = width;
}
public double getLength() {
return length;
}
public double getWidth() {
return width;
}
}
/**
* 正方形
*/
public class Square implements Quadrilateral{
private double side;
public double getSide() {
return side;
}
public void setSide(double side) {
this.side = side;
}
public double getLength() {
return side;
}
public double getWidth() {
return side;
}
}
先定义一个四边形接口,定义getLength()和getWith()函数,让正方形类和长方形类实现这个接口。重写方法。
三、依赖倒转原则
在开发中比较常见:
高层模块不直接依赖底层模块,两者都应该依赖于其抽象,要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
【例】组装电脑
现要组装一台电脑,需要配件cpu,硬盘,内存条。只有这些配置都有了,计算机才能正常的运行。选择cpu有很多选择,如Intel,AMD等,硬盘可以选择希捷,西数等,内存条可以选择金士顿,海盗船等。这个要求用代码实现出来,符合依赖倒置原则
先定义cpu和硬盘,内存接口:
java
// CPU接口
interface CPU {
String getBrand();
String getModel();
double getClockSpeed();
void process();
}
// 硬盘接口
interface HardDisk {
String getBrand();
String getModel();
int getCapacity();
void readData();
void writeData();
}
// 内存接口
interface Memory {
String getBrand();
String getModel();
int getSize();
int getSpeed();
void storeData();
}
实现类:
java
// CPU实现类
class IntelCPU implements CPU {
private String model;
private double clockSpeed;
public IntelCPU(String model, double clockSpeed) {
this.model = model;
this.clockSpeed = clockSpeed;
}
@Override
public String getBrand() {
return "Intel";
}
@Override
public String getModel() {
return model;
}
@Override
public double getClockSpeed() {
return clockSpeed;
}
@Override
public void process() {
System.out.println(getBrand() + " " + model + " CPU正在处理数据,主频:" + clockSpeed + "GHz");
}
}
class AMDCPU implements CPU {
private String model;
private double clockSpeed;
public AMDCPU(String model, double clockSpeed) {
this.model = model;
this.clockSpeed = clockSpeed;
}
@Override
public String getBrand() {
return "AMD";
}
@Override
public String getModel() {
return model;
}
@Override
public double getClockSpeed() {
return clockSpeed;
}
@Override
public void process() {
System.out.println(getBrand() + " " + model + " CPU正在处理数据,主频:" + clockSpeed + "GHz");
}
}
// 硬盘实现类
class SeagateHardDisk implements HardDisk {
private String model;
private int capacity; // GB
public SeagateHardDisk(String model, int capacity) {
this.model = model;
this.capacity = capacity;
}
@Override
public String getBrand() {
return "Seagate";
}
@Override
public String getModel() {
return model;
}
@Override
public int getCapacity() {
return capacity;
}
@Override
public void readData() {
System.out.println(getBrand() + " " + model + " 硬盘正在读取数据,容量:" + capacity + "GB");
}
@Override
public void writeData() {
System.out.println(getBrand() + " " + model + " 硬盘正在写入数据,容量:" + capacity + "GB");
}
}
class WD_HardDisk implements HardDisk {
private String model;
private int capacity; // GB
public WD_HardDisk(String model, int capacity) {
this.model = model;
this.capacity = capacity;
}
@Override
public String getBrand() {
return "Western Digital";
}
@Override
public String getModel() {
return model;
}
@Override
public int getCapacity() {
return capacity;
}
@Override
public void readData() {
System.out.println(getBrand() + " " + model + " 硬盘正在读取数据,容量:" + capacity + "GB");
}
@Override
public void writeData() {
System.out.println(getBrand() + " " + model + " 硬盘正在写入数据,容量:" + capacity + "GB");
}
}
// 内存实现类
class KingstonMemory implements Memory {
private String model;
private int size; // GB
private int speed; // MHz
public KingstonMemory(String model, int size, int speed) {
this.model = model;
this.size = size;
this.speed = speed;
}
@Override
public String getBrand() {
return "Kingston";
}
@Override
public String getModel() {
return model;
}
@Override
public int getSize() {
return size;
}
@Override
public int getSpeed() {
return speed;
}
@Override
public void storeData() {
System.out.println(getBrand() + " " + model + " 内存正在存储数据,容量:" + size + "GB,频率:" + speed + "MHz");
}
}
class CorsairMemory implements Memory {
private String model;
private int size; // GB
private int speed; // MHz
public CorsairMemory(String model, int size, int speed) {
this.model = model;
this.size = size;
this.speed = speed;
}
@Override
public String getBrand() {
return "Corsair";
}
@Override
public String getModel() {
return model;
}
@Override
public int getSize() {
return size;
}
@Override
public int getSpeed() {
return speed;
}
@Override
public void storeData() {
System.out.println(getBrand() + " " + model + " 内存正在存储数据,容量:" + size + "GB,频率:" + speed + "MHz");
}
}
计算机类,依赖于cpu和磁盘和内存:
java
class Computer {
// 依赖抽象,不依赖具体实现
private CPU cpu;
private HardDisk hardDisk;
private Memory memory;
// 通过构造函数注入依赖
public Computer(CPU cpu, HardDisk hardDisk, Memory memory) {
this.cpu = cpu;
this.hardDisk = hardDisk;
this.memory = memory;
}
// 也可以通过setter方法注入依赖
public void setCpu(CPU cpu) {
this.cpu = cpu;
}
public void setHardDisk(HardDisk hardDisk) {
this.hardDisk = hardDisk;
}
public void setMemory(Memory memory) {
this.memory = memory;
}
public void start() {
System.out.println("=== 计算机启动中 ===");
System.out.println("检查硬件配置:");
System.out.println("CPU: " + cpu.getBrand() + " " + cpu.getModel());
System.out.println("硬盘: " + hardDisk.getBrand() + " " + hardDisk.getModel());
System.out.println("内存: " + memory.getBrand() + " " + memory.getModel());
System.out.println();
}
public void run() {
System.out.println("=== 计算机运行中 ===");
cpu.process();
memory.storeData();
hardDisk.readData();
System.out.println();
}
public void shutdown() {
System.out.println("=== 计算机关闭中 ===");
hardDisk.writeData();
System.out.println("数据已保存,正在关闭...");
}
public void showSpecifications() {
System.out.println("=== 计算机配置详情 ===");
System.out.println("CPU:");
System.out.println(" 品牌: " + cpu.getBrand());
System.out.println(" 型号: " + cpu.getModel());
System.out.println(" 主频: " + cpu.getClockSpeed() + " GHz");
System.out.println("\n硬盘:");
System.out.println(" 品牌: " + hardDisk.getBrand());
System.out.println(" 型号: " + hardDisk.getModel());
System.out.println(" 容量: " + hardDisk.getCapacity() + " GB");
System.out.println("\n内存:");
System.out.println(" 品牌: " + memory.getBrand());
System.out.println(" 型号: " + memory.getModel());
System.out.println(" 容量: " + memory.getSize() + " GB");
System.out.println(" 频率: " + memory.getSpeed() + " MHz");
System.out.println();
}
}
四、接口隔离原则(单一职责原则)
客户端不应该被迫依赖于它不使用的方法;一个类对另一个类的依赖应该建立在最小的接口上。
例:
java
// ==================== 第一层:基本行为接口 ====================
/**
* 基础工作接口 - 只包含最基本的工作行为
*/
interface Workable {
void work();
}
/**
* 可进食接口 - 只包含进食行为
*/
interface Eatable {
void eat();
}
/**
* 可睡眠接口 - 只包含睡眠行为
*/
interface Sleepable {
void sleep();
}
// ==================== 第二层:专业能力接口 ====================
/**
* 程序员接口 - 包含编程相关行为
*/
interface Programmer {
void code();
void debug();
}
/**
* 设计师接口 - 包含设计相关行为
*/
interface Designer {
void design();
void prototype();
}
/**
* 测试工程师接口 - 包含测试相关行为
*/
interface Tester {
void test();
void reportBug();
}
/**
* 运维工程师接口 - 包含部署相关行为
*/
interface DevOps {
void deploy();
void monitor();
}
// ==================== 具体实现类 ====================
/**
* 全栈工程师 - 实现多个相关接口
*/
class FullStackDeveloper implements Workable, Programmer, Designer, Tester, DevOps {
@Override
public void work() {
System.out.println("全栈工程师正在工作");
}
@Override
public void code() {
System.out.println("全栈工程师正在编写代码");
}
@Override
public void debug() {
System.out.println("全栈工程师正在调试代码");
}
@Override
public void design() {
System.out.println("全栈工程师正在设计系统架构");
}
@Override
public void prototype() {
System.out.println("全栈工程师正在制作原型");
}
@Override
public void test() {
System.out.println("全栈工程师正在进行单元测试");
}
@Override
public void reportBug() {
System.out.println("全栈工程师正在报告缺陷");
}
@Override
public void deploy() {
System.out.println("全栈工程师正在部署应用");
}
@Override
public void monitor() {
System.out.println("全栈工程师正在监控系统");
}
}
/**
* 人类员工 - 按需实现接口
*/
class HumanEmployee implements Workable, Eatable, Sleepable {
private String name;
private String position;
public HumanEmployee(String name, String position) {
this.name = name;
this.position = position;
}
@Override
public void work() {
System.out.println(name + "(" + position + ")正在工作");
}
@Override
public void eat() {
System.out.println(name + "正在员工餐厅吃饭");
}
@Override
public void sleep() {
System.out.println(name + "正在休息室小憩");
}
}
/**
* 机器人程序员 - 只实现必要的接口
*/
class RobotProgrammer implements Workable, Programmer {
private String model;
public RobotProgrammer(String model) {
this.model = model;
}
@Override
public void work() {
System.out.println(model + "机器人正在工作");
}
@Override
public void code() {
System.out.println(model + "机器人正在高效编写代码");
}
@Override
public void debug() {
System.out.println(model + "机器人正在分析并修复bug");
}
}
/**
* 专职测试机器人 - 专注测试工作
*/
class TestingRobot implements Workable, Tester {
@Override
public void work() {
System.out.println("测试机器人开始工作");
}
@Override
public void test() {
System.out.println("测试机器人正在执行自动化测试");
}
@Override
public void reportBug() {
System.out.println("测试机器人正在生成测试报告");
}
}
/**
* 管理类 - 只依赖最小接口
*/
class WorkManager {
public void manageWork(Workable worker) {
worker.work();
}
}
class Restaurant {
public void serveFood(Eatable eater) {
eater.eat();
}
}
class RestRoom {
public void allowRest(Sleepable sleeper) {
sleeper.sleep();
}
}
代码中创建了Workable、Eatable、Sleepable等基本行为接口和Programmer、Designer等专业技能接口,不同类按需组合实现。机器人程序员只实现Workable和Programmer接口而无需实现Eatable,人类员工则根据角色组合不同接口。WorkManager、Restaurant等客户端类只依赖各自需要的最小接口,避免了强迫类实现不相关方法,提高了系统的灵活性和可维护性。