软件设计的7大原则
1、开放-封闭原则
对模块、类、函数扩展开发、对修改关闭。强调使用抽象构建框架,用实现扩展细节,从而提高软件系统的复用性和扩展性。开闭原则是面向对象设计中最基础的设计原则,指导我们如何构建稳定灵活的系统。
例如:在版本更新的时候,尽可能的不修改已有源代码,通过新增类来扩展功能。
/**
* 支付
*/
public interface Payment {
/**
* 扣款
* @param amount 金额
* @return
*/
String pay(int amount);
}
public class Alipay implements Payment{
public String pay(int amount) {
return "扣款"+amount+"元";
}
}
public class DiscountAlipay extends Alipay{
/**
* 打折优惠
* @param totalPrice
* @param discountAmount
* @return
*/
public String discount(int totalPrice, int discountAmount){
return pay(totalPrice - discountAmount);
}
}
2、依赖倒置原则
设计代码结构时,高层模块不应该依赖底层的模块,二者应该依赖其抽象,让细节依赖抽象。通过依赖倒置原则,可以减少类与类之间的耦合性,提高系统的稳定性,可读性和可维护性,降低修改给程序带来的风险。
例如:用户扫描二维码后可以选择多种支付方式
public class WechatPay implements Payment{
public String pay(int amount) {
return null;
}
}
public class User {
private String name;
private Payment payment;
public void setName(String name) {
this.name = name;
}
public void setPayment(Payment payment) {
this.payment = payment;
}
public String pay(int amount){
return payment.pay(amount);
}
}
public class AppTest
{
public static void main(String[] args) {
User tom = new User();
tom.setName("tom");
tom.setPayment(new Alipay());
tom.pay(100);
User jack= new User();
jack.setName("jack");
jack.setPayment(new WechatPay ());
tom.pay(200);
}
}
3、单一职责原则
指一个类或一个方法,只负责一个职责,避免修改其中一个类或一个方法逻辑,造成另外一个类或方法功能故障。
职责划分可以对功能解耦,降低系统复杂度,提高维护性性、可读性。
例如:上面的例子中,Alipay和WechatPay,支付的实现细节不同,对支付方式的不同,划分了不同的类。
4、接口隔离原则
使用多个专门的总接口,而不使用一个总的接口,客户端不应该依赖不需要的接口。设计接口是应该遵循的几个点:
(1)类一对一的依赖应该建立在最小的接口之上
(2)建立单一接口,不要建立臃肿的接口
(3)尽量细化接口,接口中的方法数量要适度。
接口隔离原则复合高类聚,低耦合的设计思想,类具有良好的可读性、可扩展性、可维护性。接口设计的时候要多花时间思考业务模型,对可能发生的变更提前预判,所以抽象对模型的理解非常重要。
public interface Animal {
void eat();
void fly();
void swing();
}
public class Bird implements Animal {
public void eat() {
System.out.println("喜欢吃虫子!");
}
public void fly() {
System.out.println("鹰击长空");
}
public void swing() {
}
}
public class Dog implements Animal {
public void eat() {
System.out.println("喜欢磕骨头");
}
public void fly() {
}
public void swing() {
System.out.println("擅长游泳");
}
}
public class Cat implements Animal{
public void eat() {
System.out.println("喜欢吃鱼");
}
public void fly() {
}
public void swing() {
}
}
每个类都有空着的方法,dog和cat显然是不要fly方法的,通过设计不同功能的接口进行改糙,如下:
public interface Flyable {
void fly();
}
public interface Eatable {
void eat();
}
public interface Swimming {
void swing();
}
public class Bird implements Flyable,Eatable {
public void eat() {
System.out.println("喜欢吃虫子!");
}
public void fly() {
System.out.println("鹰击长空");
}
}
public class Dog implements Eatable,Swimming {
public void eat() {
System.out.println("喜欢磕骨头");
}
public void swing() {
System.out.println("擅长游泳");
}
}
public class Cat implements Eatable{
public void eat() {
System.out.println("喜欢吃鱼");
}
}
5、迪米特法则
一个类对其他类应该有最少的了解,又叫最少知道原则,降低累于类之间的耦合性。迪米特法则强调只和朋友交流,不和陌生人说话,类的成员变量、方法的输入输出参数称为朋友,方法体内部的类不属于朋友。
例如:Boss需要季度,年度报表,只需要找到数据部门的主管,主管让下面擅长做报表的员工制作报表,然后主管反馈报表给Boss,Boss不需要自己去了解报表是怎么做的。
6、里式替换原则
代码编写中适用于父类的地方,那么一定适用子类。所以引用父类方法的地方必须可以透明底适用子类,子类对象可以替换父类对象,而程序逻辑不变。
引申意思:子类可以扩展父类的功能,但不能改变父类原有功能。
(1)子类可以实现父类的抽象方法,不能覆盖父类的非抽象方法
(2)子类可以增加自己特有的方法
(3)当子类重载父类的方法时,方法的前置条件(方法输入参数)比父类更宽松
(4)子类实现父类方法时,方法的后置添加(方法输出值)比父类更严格或相等。
(3)和(4)指方法的的开发程度,父类是protected,子类至少应该是protectd,宽松就是public; 参数如果是String,那么子类实现和重载的方法至少应该是String,宽松是Object;返回值父类是String,严格就是String的子类,相等就是String。
里式替换的有点:
(1)约束继承泛滥,开闭原则的一种体现
(2)增强程序的健壮性,同时变更做的非常好的兼容性,提高程序维护性,扩展性
7、合成复用原则
尽量使用对象组合、聚合,而不是继承达到软件复用的目的。可以降低类与类之间的耦合度,让程序更加灵活。
继承叫做白箱复用,父类把所有的细节暴露给子类。
组合/聚合叫做黑箱复用,对类以外的对象无法获取到实现细节。
例如:以Connection连接为例
public interface Connection {
}
public class DBConnection implements Connection {
}
public class HttpConnection implements Connection{
}
public class ProductServiceImpl {
private Connection connection;
}
service最开始功能只有从数据库查询时,现在需要使用http连接从第三方查询是,增加HttpConnection的对象持有,就可以实现功能的扩展,而不是使用继承。
总结:
设计原则是学习设计模式的基础,实际开发过程中不一定要求所有的代码都遵循设计规则,考虑到人力、时间、成本、质量等多方面的因素,适当遵循设计原则。
上一篇: CocoaPods的spec