軟體設計的七大原則
七大設計原則
開閉原則
依賴導倒置原則
單一職責原則
介面隔離原則
迪米特原則
里氏替換原則
合成複用原則
設計模式-建立型模式
工廠方法模式
抽象工廠模式
建造者模式
單例模式
原型模式
設計模式-結構性模式
介面卡模式
裝飾者模式
代理模式
外觀模式
橋接模式
組合模式
享元模式
設計模式-行為型模式
策略模式
模板方法模式
觀察者模式
訪問者模式
迭代器模式
責任鏈模式
中介者模式
直譯器模式
狀態模式
命令模式
備忘錄模式
開閉原則
定義:一個軟體實體如類,模組和函式應該對擴充套件開放,對修改關閉。
用抽象構建框架,用實現擴充套件細節
優點:提高軟體系統的可複用性及可維護性
下面給一個程式碼體現開閉原則:
package principle.openClose;
public interface ICourse {
Integer getId();
String getName();
Double getPrice();
}
package principle.openClose; public class javaCoure implements ICourse { private Integer id; private String name; private Double price; public javaCoure(Integer id, String name, Double price) { this.id = id; this.name = name; this.price = price; } @Override public Integer getId() { return this.id; } @Override public String getName() { return this.name; } @Override public Double getPrice() { return this.price; } }
package principle.openClose;
public class Test {
public static void main(String[] args) {
ICourse javaCoures = new javaCoure(88,"語文",100d);
System.out.println("課程id:"+javaCoures.getId()+" 課程名稱:"+javaCoures.getName()+" 課程價格:"+javaCoures.getPrice());
}
}
現在價格要變的話怎麼寫呢?
方法一:在ICourse中加入如下程式碼
Double getDiscountPrice();
在javaCourse中新增如下程式碼
public Double getDiscountPrice(){
return this.price*0.8;
}
有啥問題呢,如果課程很多,那麼所有的課程都要加上這些價格變化的方法。介面不能隨便動,否則作為契約的作用就失去了。
方法二:直接在得到價格的方法中改
@Override
public Double getPrice() {
return this.price;
}
改成:
@Override
public Double getPrice() {
return this.price*0.8;
}
有啥問題呢?看起來比上面更簡潔了。和上面一樣,如果課程很多的話,修改的地方也很多,如果需求還要你顯示原價,這就行不通了吧。在複雜一點,如果課程》300元的才進行打折活動,如果後面還加了優惠券的活動呢?
方法三:終極方法
增加一個方法,繼承javaCoure
package principle.openClose;
public class JavaDiscountCourse extends javaCoure {
public JavaDiscountCourse(Integer id, String name, Double price) {
super(id, name, price);
}
@Override
public Double getPrice() {
return super.getPrice()*0.8;
}
public Double getOriginPrice(){
return super.getPrice();
}
}
依賴倒置原則
定義:高層模組不應該依賴低層模組,二者應該依賴其抽象。
抽象不應該依賴細節;細節應該依賴緩抽象
針對介面程式設計,不應該針對實現程式設計
優點:可以減少類間的耦合性,提高系統穩定性,提高程式碼可讀性和可維護性,可降低修改程式所造成的風險。
請看下面程式碼:
package design.dependenceInVersion;
public class Xwy {
public void studyJavaCourse(){
System.out.println("xwy在學習java課程");
}
public void studyFECourse(){
System.out.println("xwy在學習前端課程");
}
}
再寫一個測試類:
package design.dependenceInVersion;
public class Test {
public static void main(String[] args) {
Xwy xwy = new Xwy();
xwy.studyFECourse();
xwy.studyJavaCourse();
}
}
如果要再學習一個課程,就需要在Xwy類中加一個方法。
這是面向實現程式設計,實現類需要經常修改,擴充套件性差。
下面有幾種改進的方法
package design.dependenceInVersion;
public interface Icourse {
void studyCourse() ;
}
package design.dependenceInVersion;
public class JavaCourse implements Icourse {
@Override
public void studyCourse() {
System.out.println("xwy在學習java課程");
}
}
package design.dependenceInVersion;
public class EFCourse implements Icourse {
@Override
public void studyCourse() {
System.out.println("xwy在學習前端課程");
}
}
package design.dependenceInVersion;
public class Xwy {
private Icourse icourse;
//v1
// public void studyFECourse() {
// System.out.println("FE課程");
// }
//
// public void studyJavaCourse() {
// System.out.println("java課程");
// }
//v2
// public void studyXwyCourse(Icourse icourse){
// icourse.studyCourse();
// }
//v3
// public Xwy(Icourse icourse) {
// this.icourse = icourse;
// }
//
// public void studyXwyCourse(){
// icourse.studyCourse();
// }
//v4
public void setIcourse(Icourse icourse) {
this.icourse = icourse;
}
public Xwy() {
}
public void studyXwyCourse(){
icourse.studyCourse();
}
}
package design.dependenceInVersion;
public class Test {
public static void main(String[] args) {
//v1
// Xwy xwy = new Xwy();
// xwy.studyFECourse();
// xwy.studyJavaCourse();
// //v2
// Xwy xwy = new Xwy();
// xwy.studyXwyCourse(new JavaCourse());
// xwy.studyXwyCourse(new EFCourse());
//v3
// Xwy xwy = new Xwy(new JavaCourse());
// xwy.studyXwyCourse();
//v4
Xwy xwy = new Xwy();
xwy.setIcourse(new JavaCourse());
xwy.studyXwyCourse();
xwy.setIcourse(new EFCourse());
xwy.studyXwyCourse();
}
}
上面有4種寫法
第一種:直接實現Icoure介面,在客戶端需要哪個方法就調哪個方法,Xwy xwy = new Xwy();
xwy.studyFECourse();
xwy.studyJavaCourse();
第二種方法:使用介面方法注入
Xwy xwy = new Xwy();
xwy.studyXwyCourse(new JavaCourse());
xwy.studyXwyCourse(new EFCourse());
第三種方法:使用構造器
Xwy xwy = new Xwy(new JavaCourse());
xwy.studyXwyCourse();
第四種方法:使用set注入
Xwy xwy = new Xwy();
xwy.setIcourse(new JavaCourse());
xwy.studyXwyCourse();
xwy.setIcourse(new EFCourse());
xwy.studyXwyCourse();
單一職責原則
- 定義:不要存在多於一個導致類變更的原因
- 一個類/ 介面/方法只負責一項職責
- 優點:降低類的複雜度、提高類的可讀性,提高系統的可維護性、降低變更的風險
介面隔離原則
- 定義:用多個專門的介面,二不使用單一的總介面,客戶端不應該依賴他不需要的介面
- 一個類對應一個類的依賴應該建立在最小的介面上
- 建立單一介面,不要建立龐大臃腫的介面
- 儘量細化介面,介面中的方法儘量少
- 適度原則,一定要適度
- 優點:符合高內聚低耦合的設計思想,從而使得類具有很好的可讀性、可擴充套件性和可維護性
下面來先看下程式碼
package design.interfaceGeragion;
public interface IAnimalAction {
void eat();
void fly();
void swim();
}
package design.interfaceGeragion;
public class Dog implements IAnimalAction {
@Override
public void eat() {
}
@Override
public void fly() {
}
@Override
public void swim() {
}
}
package design.interfaceGeragion;
public class Bird implements IAnimalAction {
@Override
public void eat() {
}
@Override
public void fly() {
}
@Override
public void swim() {
}
}
再來看下面的程式碼
package design.interfaceGeragion;
public interface IEatAnimalAction {
void eat();
}
package design.interfaceGeragion;
public interface IFlayAnimalAction {
void fly();
}
package design.interfaceGeragion;
public interface ISwrimAction {
void swim();
}
package design.interfaceGeragion;
public class Bird implements IEatAnimalAction,IFlayAnimalAction {
@Override
public void eat() {
}
@Override
public void fly() {
}
}
package design.interfaceGeragion;
public class Dog implements IEatAnimalAction,ISwrimAction {
@Override
public void eat() {
}
@Override
public void swim() {
}
}
這個程式碼比上個程式碼更加靈活
迪米特原則
- 定義:一個物件對其他物件保持最少的瞭解。又叫最少知道原則
- 儘量降低類與類之間的耦合
- 優點:降低類之間的耦合
- 強調只和朋友交流
- 朋友:出現在成員變數、方法的輸入、輸出引數中的類稱為成員朋友類,而出現在方法體內部的類不屬於朋友類
看下面的程式碼
package design.dimiter;
import java.util.List;
public class TeamLeader {
public void checkNumberOfCourse(List<Coures> couresList){
System.out.println("線上課程的數量是:"+couresList.size());
}
}
package design.dimiter;
public class Coures {
}
package design.dimiter;
import java.util.ArrayList;
import java.util.List;
public class Boss {
public void commandCheakNumber(TeamLeader teamLeader){
List<Coures> couresList = new ArrayList<>();
for (int i=0;i<20;i++){
couresList.add(new Coures());
}
teamLeader.checkNumberOfCourse(couresList);
}
}
package design.dimiter;
public class Test{
public static void main(String[] args) {
Boss boss = new Boss();
TeamLeader teamLeader = new TeamLeader();
boss.commandCheakNumber(teamLeader);
}
}
idea生成的類圖如下:
course不應該和boss產生交集,把boss裡的程式碼:
List<Coures> couresList = new ArrayList<>();
for (int i=0;i<20;i++){
couresList.add(new Coures());
}
移到TeamLeader中