七大软件设计原则
设计模式大约 7 分钟
七大软件设计原则
设计模式是近现代编码项目实施过程中经验的总结,主要是为了应对程序的耦合,内聚,维护性,灵活性的应用。
本文中将对业界流行的七中设计模式进行阐述,归纳。
开闭原则
概述
强调的是用抽象构建框架,用实现扩展细节
场景
我们版本更新,尽可能不修改原代码,但是可以增加新功能。
优点
保持软件产品的稳定性
不影响原有测试代码的运行
使代码更具模块化,易于维护
提高开发效率
栗子
public interface Icourse {
/**
* getId
*
* @return
*/
Long getId();
/**
* getName
*
* @return
*/
String getName();
/**
* getPrice
*
* @return
*/
Double getPrice();
}
public class JavaCourse implements Icourse {
private Long id;
private String name;
private Double price;
public JavaCourse(Long id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
@Override
public Long getId() {
return id;
}
@Override
public String getName() {
return name;
}
@Override
public Double getPrice() {
return price;
}
}
public class JavaDiscountCourse extends JavaCourse {
public JavaDiscountCourse(Long id, String name, Double price) {
super(id, name, price);
}
public Double getOriginalPrice() {
return super.getPrice();
}
@Override
public Double getPrice() {
return super.getPrice() * 0.1;
}
}
public class OpenCloseDemoTest {
public static void main(String[] args) {
/**
* 开闭原则,定义一个接口,不同的实现,可以做到, 对新增开放,对修改关闭,低耦合
*/
Icourse icourse = new JavaDiscountCourse(1L, "sz", 1D);
Double price = icourse.getPrice();
System.out.println(price);
Icourse original = new JavaCourse(1L, "sz", 1D);
Double price1 = original.getPrice();
System.out.println(price1);
}
}
依赖倒置
概述
高层模块不应该依赖低层模块
,二者都应该依赖其抽象。 抽象不应该依赖细节,细节应该依赖抽象。 针对接口编程,不要针对实现编程。
场景
A a =new A(new B());
优点
减少类之间的耦合性。
提高系统的稳定性。
提高代码可读性和可维护性。
可降低修改程序所造成的风险。
栗子
public interface Icourse {
/**
* study
*/
void study();
}
public class JavaCourse implements Icourse {
@Override
public void study() {
System.out.println("xq正在学习java课程");
}
}
public class PythonCourse implements Icourse {
@Override
public void study() {
System.out.println("xq正在学习python课程");
}
}
public class Tom {
/**
* 啥是依赖倒置了,就是本来我是tom,我要去学课程,我直接在tom的类里面去写,我要学java,我要学python,
* 学习课程,是抽象的,还是行为,于是,课程抽象为接口,java,phthotn是其实现,
* tom学那个课程,应该是那个课程的抽象,她不应该依赖是具体的那门课程
* <p>
* 即,高层模块不依赖底层模块,二者依赖其抽象,
* 抽象不依赖细节,细节依赖抽象,
* 减少耦合,提高稳定,增强,代码可读性,可维护性
*/
private Icourse icourse;
public void setIcourse(Icourse icourse) {
this.icourse = icourse;
}
public void studyJavaCourse() {
System.out.println("xq正在学习java课程");
}
public void studyPythonCourse() {
System.out.println("xq正在学习python课程");
}
// 未有依赖倒置前 1.0 版本
// public static void main(String[] args) {
// Tom tom = new Tom();
// tom.studyJavaCourse();
// tom.studyPythonCourse();
// }
public void study(Icourse icourse) {
icourse.study();
}
public void studyTwo() {
icourse.study();
}
// 2.0 版本
// public static void main(String[] args) {
// Tom tom = new Tom();
// 直接new
// tom.study(new JavaCourse());
// }
// 3.0版本
public static void main(String[] args) {
Tom tom = new Tom();
// 依赖注入通过setter
tom.setIcourse(new JavaCourse());
tom.studyTwo();
}
}
单一职责&接口隔离
概述
不要存在多于一个导致类变更的原因。
一个类/接口/方法只负责一项职责。
场景
支付业务的service就不需要写上发邮件的具体代码。
优点
降低类的复杂度。
提高类的可读性。
提高系统的可维护性。
降低变更引起的风险。
栗子
public interface IAnimal {
/**
* eat
*/
void eat();
/**
* fly
*/
void fly();
/**
* swim
*/
void swim();
}
public class Dog implements IAnimal {
/**
* eat
*/
@Override
public void eat() {
}
/**
* fly
*/
@Override
public void fly() {
// 此时,狗根本就不能飞!,如果用一个统一的接口的话,接口定义行为错误
}
@Override
public void swim() {
}
}
public class Bird implements IAnimal {
@Override
public void eat() {
}
@Override
public void fly() {
}
@Override
public void swim() {
// 此时,鸟根本就不能泳!,如果用一个统一的接口的话,会出现脏的行为
}
}
- 接口隔离后
public interface IEatAnimal {
/**
* eat
*/
void eat();
}
public interface ISwimAnimal {
/**
* swim
*/
void swim();
}
public interface FlyAnimal {
/**
* fly
*/
void fly();
}
public class DogTow implements IEatAnimal, ISwimAnimal {
@Override
public void eat() {
System.out.println("狗会吃");
}
@Override
public void swim() {
System.out.println("狗会游");
}
}
- 接口隔离,根据不同的行为,制定不定的接口,不用一个单一的接口,确定所有的行为.
迪米特法则
概述
只和朋友交流(成员变量、方法输入输出参数),不和陌生人说话,控制好访问修饰符
场景
老板让项目经理做事,不需要知道具体做的逻辑
优点
降低类与类之间的耦合
栗子
public class Course {}
public class Employee {
public void checkNumberOfCourses(List<Course> courses) {
System.out.println("目前已经发布的课程数量:" + courses.size());
}
}
public class TeamLeader {
public void commandCheckNumber(Employee employee) {
List<Course> list = new ArrayList<Course>();
for (int i = 0; i < 20; i++) {
// 迪米特法则,有些对象,与我产生不了关系,就不应该放在这里
list.add(new Course());
}
employee.checkNumberOfCourses(list);
}
public static void main(String[] args) {
TeamLeader teamLeader = new TeamLeader();
Employee employee = new Employee();
teamLeader.commandCheckNumber(employee);
}
}
- 修改后
public class EmployeeTow {
public void checkNumberOfCourses() {
List<Course> list = new ArrayList<Course>();
for (int i = 0; i < 20; i++) {
// 迪米特法则,有些对象,与我产生不了关系,就不应该放在这里
list.add(new Course());
}
System.out.println("目前已经发布的课程数量:" + list.size());
}
}
public class TeamLeaderTow {
public void commandCheckNumber(EmployeeTow employeeTow) {
employeeTow.checkNumberOfCourses();
}
public static void main(String[] args) {
/**
* 这些修改以后,就是符合迪米特法则,我是leader我只需要知道,
* 我的小弟,在干啥,至于,我小弟在具体干什么,我不需要知道
* 最少知道原则
*
*/
TeamLeaderTow teamLeader = new TeamLeaderTow();
teamLeader.commandCheckNumber(new EmployeeTow());
}
}
里氏替换
概述
在程序中将一个父类的对象改成其继承类,并不影响程序运行。
将子类适应的程序改成父类,则程序可能会出现异常。
场景
用来对类跟类之间继承的一种约束
优点
规范使用继承
栗子
public class Rectangle {
private Long height;
private Long width;
public Long getHeight() {
return height;
}
public void setHeight(Long height) {
this.height = height;
}
public Long getWidth() {
return width;
}
public void setWidth(Long width) {
this.width = width;
}
}
public class Square extends Rectangle {
private Long length;
public Long getLength() {
return length;
}
public void setLength(Long length) {
this.length = length;
}
@Override
public Long getHeight() {
return getLength();
}
@Override
public void setHeight(Long height) {
setLength(height);
}
@Override
public Long getWidth() {
return getLength();
}
@Override
public void setWidth(Long width) {
setLength(width);
}
}
public class Test01 {
public static void reSize(Rectangle rectangle) {
while (rectangle.getWidth() >= rectangle.getHeight()) {
rectangle.setHeight(rectangle.getHeight() + 1);
System.out.println("width:" + rectangle.getWidth() + ",height:" + rectangle.getHeight());
}
System.out.println("resize end ,width:" + rectangle.getWidth() + ",height:" + rectangle.getHeight());
}
// public static void main(String[] args) {
// Rectangle rectangle = new Rectangle();
// rectangle.setWidth(20L);
// rectangle.setHeight(10L);
// reSize(rectangle);
// }
// 出现了死循环 约束继承泛滥
public static void main(String[] args) {
Square square = new Square();
square.setLength(10L);
reSize(square);
}
}
- 修改后
public interface QuadRangle {
/**
* getWidth
* @return
*/
long getWidth();
/**
* getHeight
* @return
*/
long getHeight();
}
public class RectRangleTwo implements QuadRangle{
private long width;
private long height;
public void setWidth(long width) {
this.width = width;
}
public void setHeight(long height) {
this.height = height;
}
@Override
public long getWidth() {
return width;
}
@Override
public long getHeight() {
return height;
}
}
public class SquareTwo implements QuadRangle {
private long length;
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
@Override
public long getWidth() {
return length;
}
@Override
public long getHeight() {
return length;
}
}
public class TestSubstitutuinDemo {
public static void reSize(RectRangleTwo rectangle) {
while (rectangle.getWidth() >= rectangle.getHeight()) {
rectangle.setHeight(rectangle.getHeight() + 1);
System.out.println("width:" + rectangle.getWidth() + ",height:" + rectangle.getHeight());
}
System.out.println("resize end ,width:" + rectangle.getWidth() + ",height:" + rectangle.getHeight());
}
public static void main(String[] args) {
SquareTwo rectRangleTwo = new SquareTwo();
rectRangleTwo.setLength(10);
// 为了约束继承泛滥!
// reSize(rectRangleTwo);
}
}
合成复用
概述
多使用has-a对象组合;聚合 contains-a 聚合 而不是继承 ,因为继承是白盒,暴露了很多信息。 聚合,组合,则是黑盒,可以降低,类之间的耦合关系,一个类对另一个类影响较少继承会暴露信息。
场景
获取数据库连接的时候,同一个行为,不同的实现,根据不同的实现来判断行为。
优点
降低,类之间的耦合关系。
栗子
public class DbConnection {
public String getConnection() {
return "返回mysql数据链接";
}
}
public class ProductDao {
private DbConnection dbConnection;
public ProductDao(DbConnection dbConnection) {
this.dbConnection = dbConnection;
}
public void addProduct() {
String conncetion = dbConnection.getConnection();
System.out.println("获取 " + conncetion + ",加入产品");
}
}
public class CompositeReUseTest {
// 1.0版本
public static void main(String[] args) {
ProductDao productDao = new ProductDao(new DbConnection());
productDao.addProduct();
}
}
- 修改后
public abstract class DbConnection2 {
/**
* getDbConnection
* @return
*/
public abstract String getDbConnection();
}
public class MysqlConnection extends DbConnection2 {
@Override
public String getDbConnection() {
return "返回mysql数据库链接";
}
}
public class OracleConnection extends DbConnection2 {
@Override
public String getDbConnection() {
return "返回oracle数据库链接";
}
}
public class ProductDao1 {
private DbConnection2 dbConnection2;
public ProductDao1(DbConnection2 dbConnection2) {
this.dbConnection2 = dbConnection2;
}
public void addProduct() {
System.out.println("获取链接:" + dbConnection2.getDbConnection() + "插入产品");
}
}
public class CompositeReUseTest {
public static void main(String[] args) {
ProductDao1 productDao1 = new ProductDao1(new MysqlConnection());
productDao1.addProduct();
ProductDao1 productDao2 = new ProductDao1(new OracleConnection());
productDao2.addProduct();
}
}