淺談設計模式的六大原則
一,單一職責原則:就一個類而言,應該僅有一個引起它變化的原因(就是實現類要責任單一)
英文--Single Responsibility Principle
簡寫:SRP
舉個例子:
父類:Animal
public class Animal {
void move(String animal){
System.out.println(animal + "是主要用腳來移動的");
}
}
測試類:
輸出:<pre name="code" class="java">public class SRPTest { public static void main(String[] args) { Animal animal = new Animal(); animal.move("狗"); animal.move("貓"); animal.move("老鼠"); } }
狗是主要用腳來移動的
貓是主要用腳來移動的
老鼠是主要用腳來移動的
那麼問題來了,當你新增鳥時,打印出,鳥主要是用腳來移動的,(但好像是翅膀,這裡假設為翅膀)
這時,需要改程式碼了:
如果這樣改:
public class Animal {
void move(String animal){
if("鳥".equals(animal)){
System.out.println(animal + "是主要靠翅膀來移動的");
}
else{
System.out.println(animal + "是主要用腳來移動的");
}
}
}
沒錯,可以真確輸出,但違背了單一職責原則,假如又要分為類似於貓頭鷹等主要靠翅膀在夜間移動的鳥,和靠翅膀在白天移動的鳥,又該如何呢,,,再分呢?這個時候就要考慮單一職責原則了:
第一種:好像有點違背,但在方法上又好像不違背:
public class Animal {
void move(String animal){
System.out.println(animal + "是主要靠翅膀來移動的");
}
void moveN(String animal){
System.out.println(animal + "是主要用翅膀來移動的");
}
}
第二種:
用兩個類,即一個類管理一個原則:
public class Animal { void move(String animal){ System.out.println(animal + "是主要靠翅膀來移動的"); } }
public class Birds {
void move(String animal) {
System.out.println(animal + "是主要靠翅膀來移動的");
}
}
測試類:
public class SRPTest {
public static void main(String[] args) {
Animal animal = new Animal();
animal.move("狗");
animal.move("貓");
animal.move("老鼠");
Birds birds = new Birds();
birds.move("鳥");
}
}
二,開放封閉原則:對擴充套件---開發 , 對更改----封閉
英文:OpenClosePrinciple
簡寫:OCP
就是說:不要更改原始碼(現有程式碼),而應該增加一個新的類(如子類等)
如版本更新等
版本更新:儘量不更改原始碼,可以增加新功能
員工遲到問題:可以制定遲到的晚下班,遲到多久就得加班多久等制度
即:上班總時長封閉,對於遲到一點開放
三,里氏代換原則:子代父,程式行為不變化(有點類似於繼承)
英文:Liskov Substitution Principle
簡寫:LSP
理解:子類必須能夠替換他們的父型別,使得父類模組在不改變的情況下,自己可以用擴充套件性
如 動物,
子:狗,貓,牛
又如一個四則運算的例子:
求加法:
package testtwo;
public class Console {
int addNumber(int a , int b){
return (a + b);
}
}
測試類:
package testtwo;
public class Test {
public static void main(String[] args) {
Console console = new Console();
int result = console.addNumber(8, 2);
System.out.println("結果是: " + result);
}
}
輸出結果:
結果是: 10
假如要先求加法再乘法呢,如 (8 + 2)* 4
那麼你可能說我直接在Console更改就行啦,但萬一,你有好多個類使用了Console的例子呢,那麼容易出錯,
於是可以新建類來繼承,Console不變,
如程式碼:
package testtwo;
public class AConsonle extends Console{
int addNumber(int a , int b){
return (a + b);
}
int mulNumber(int a , int b){
return (a * b);
}
}
測試類:
package testtwo;
public class Test {
public static void main(String[] args) {
AConsonle aConsole = new AConsonle();
int c = aConsole.addNumber(8, 2);
int result = aConsole.mulNumber(c, 4);
System.out.println("輸出結果是:" + result);
}
}
輸出:
輸出結果是:40
四:依賴倒轉(置)原則:
英文:Dependence Inversion Principle,
簡稱 DIP
理解:
(1)抽象不應該依賴細節,細節應該依賴於抽象
(針對介面程式設計,不要針對現實程式設計)
(2)高層模組不應該依賴底層模組,兩個都應該依賴抽象
抽象:指介面或者抽象類
例子1:假如高層要訪問資料庫,這時,習慣性的我們喜歡寫一個類來實現訪問資料庫的操作(低層),
即 高層-------底層--------》資料庫
但這時,突然客戶要求可以根據自己愛好選擇不同的儲存方式呢,又該如何呢?
例子2:通過程式碼例子,
package threetest;
public class Dog {
public void eat(){
System.out.println("狗正在吃飯!");
}
}
動物類:
public class Animal {
public void animal (Dog dog){
dog.eat();
}
}
測試類:
<pre name="code" class="java">package threetest;
public class Test {
public static void main(String[] args){
Animal a = new Animal();
Dog dog = new Dog();
a.animal(dog);
a.animal(dog);
a.animal(dog);
}
}
輸出結果:
狗正在吃飯!狗正在吃飯!狗正在吃飯!
那麼這個時候,突然想在測試類,再增加貓正在吃飯,該如何改呢?(增加老鼠呢、、、?)
那麼就該想到,依賴抽象,這裡以介面為例:
程式碼:
介面類Ieat:
package threetest;
public interface Ieat {
public void eat();
}
狗類:
package threetest;
public class Dog implements Ieat{
public void eat(){
System.out.println("狗正在吃飯!");
}
}
貓類:
package threetest;
public class Cat implements Ieat{
public void eat(){
System.out.println("貓正在吃飯!");
}
}
高層類:
package threetest;
public class Animal {
public void animal(Ieat ieat){
ieat.eat();
}
}
測試類:
package threetest;
public class Test {
public static void main(String[] args){
Animal a = new Animal();
Dog dog = new Dog();
Cat cat = new Cat();
a.animal(dog);
a.animal(dog);
a.animal(dog);
a.animal(cat);
a.animal(cat);
a.animal(cat);
}
}
輸出結果:
狗正在吃飯!
狗正在吃飯!
狗正在吃飯!
貓正在吃飯!
貓正在吃飯!
貓正在吃飯!
由此可見:高層類Animal依賴於抽象(這裡是介面)
底層類 :Cat , Dog 也依賴於抽象(這裡是介面)
五,迪米特法則:降低類之間的耦合
英文(Law of Demeter,LoD)也稱為最少知識原則(Least Knowledge Principle,LKP)
根本思想:是強調了類之間的鬆耦合,
.....類對自己依賴的類知道的越少越好
......與直接朋友交流
直接朋友包括:
1)當前物件本身(this)
2)以參量形式傳入到當前物件方法中的物件
3)當前物件的例項變數直接引用的物件
4)當前物件的例項變數如果是一個聚集,那麼聚集中的元素也都是朋友
5)當前物件所建立的物件
任何一個物件,如果滿足上面的條件之一,就是當前物件的"朋友";否則就是"陌生人"。
也可以說:
出現在成員變數、方法的輸入輸出引數中的類稱為成員朋友類,而出現在方法體內部的類不屬於朋友類。
例子:
Animal類:Dog類屬於直接朋友類,因為它是通過方法的輸入輸出引數成為朋友的,當Foot在方法體count內,不屬於直接朋友
方法屬於類的行為,一個類竟然不知道他的行為與其他類有依賴關係,這就違反了迪米特法則。
package fourtest;
import java.util.ArrayList;
import java.util.List;
public class Animal {
public void count(Dog dog) {
List<Foot> list = new ArrayList<Foot>();
for(int i = 0 ; i < 10 ; i++){
list.add(new Foot());
}
dog.countFoot(list);
}
}
</pre><pre name="code" class="java">Dog類:
</pre><pre name="code" class="java"><pre name="code" class="java">package fourtest;
import java.util.List;
public class Dog {
void countFoot(List list){
System.out.println("腳共有 :" + list.size() + "只");
}
}
Foot類:這裡不寫程式碼
package fourtest;
public class Foot {
}
測試類:
package fourtest;
public class Test {
public static void main(String[] args){
Animal al = new Animal();
Dog dog = new Dog();
al.count(dog);
}
}
輸出:
腳共有 :10只
沒錯,結果沒錯,但卻違背了迪米特法則。
應該改為:
Animal類:
package fourtest;
import java.util.ArrayList;
import java.util.List;
public class Animal {
public void count(Dog dog) {
dog.countFoot();
}
}
Dog類:package fourtest;
import java.util.ArrayList;
import java.util.List;
public class Dog {
public List<Foot> list ;
public Dog(List<Foot> footList){
this.list = footList;
}
void countFoot(){
System.out.println("腳共有 :" + list.size() + "只");
}
}
Foot類不變,還是沒程式碼:
Test類:
package fourtest;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args){
List<Foot> list = new ArrayList<Foot>(); //建立一個List表,型別為Foot
for(int i = 0 ; i < 10 ; i++){ //存放資料
list.add(new Foot());
}
Dog dog = new Dog(list); //建立Dog物件,list作為引數
Animal al = new Animal(); //建立Animal物件
al.count(dog); //呼叫Animal物件的count方法,dog作為物件
}
}
輸出:
腳共有 :10只
又如圖片:
發現每個控制元件都與其他控制元件有關係,這樣如若修改一個控制元件,則可能會帶動其他控制元件,
如若用迪米特法則則可以改為:增加一箇中介(中間類)來管理,如下:
六,介面隔離原則:
英文:Interface Segregation Principle
簡寫:ISP
客戶端不應該依賴它不需要的介面,一個類對一個類的依賴應該建立在最小的介面上
注意:
(1)介面儘量小,但是要有限度。
(2)為依賴介面的類定製服務,只暴露給呼叫的類它需要的方法,它不需要的方法則隱藏起來。
(3)提高內聚,減少對外互動。使介面用最少的方法去完成最多的事情。
舉個例子:
Animal介面:
package fivetest;
interface Animal {
public void eat();
public void move();
public void sleep();
public void relax();
}
類Dog:
package fivetest;
public class Dog implements Animal{
//不是abstract,需重寫
//我們重寫前面三個方法
public void eat() {
System.out.println("狗正在吃飯");
}
public void move() {
System.out.println("狗正在移動");
}
public void sleep() {
System.out.println("狗正在睡覺");
}
public void relax() {}
}
Cat類:
package fivetest;
public class Cat implements Animal{
public void eat() {}
//這裡重寫後三個方法
public void move() {
System.out.println("貓正在移動");
}
public void sleep() {
System.out.println("貓正在睡覺");
}
public void relax() {
System.out.println("貓正在休息");
}
}
Danimal類:
package fivetest;
public class Danimal {
public void a1(Animal animal){
animal.eat();
}
public void a2(Animal animal){
animal.move();
}
public void a3(Animal animal){
animal.sleep();
}
}
Canimal類:
package fivetest;
class Canimal {
public void b2(Animal animal){
animal.move();
}
public void b3(Animal animal){
animal.sleep();
}
public void b4(Animal animal){
animal.relax();
}
}
測試類:Test
package fivetest;
public class Test {
public static void main(String[] args){
Canimal c = new Canimal();
Cat cat = new Cat();
c.b2(cat);
c.b3(cat);
c.b4(cat);
Danimal d = new Danimal();
Dog dog = new Dog();
d.a1(dog);
d.a2(dog);
d.a3(dog);
}
}
輸出結果:
貓正在移動
貓正在睡覺
貓正在休息
狗正在吃飯
狗正在移動
狗正在睡覺
利用迪米特法則改後代碼為:
介面:4個:
public interface Eat {
public void eat();
}
public interface Move {
public void move();
}
public interface Sleep {
public void sleep();
}
public interface Relax {
public void relax();
}
Dog類:
public class Dog implements Eat , Move , Sleep{
//我們重寫前面三個方法
public void eat() {
System.out.println("狗正在吃飯");
}
public void move() {
System.out.println("狗正在移動");
}
public void sleep() {
System.out.println("狗正在睡覺");
}
}
Cat類:
public class Cat implements Move , Sleep , Relax{
//這裡重寫後三個方法
public void move() {
System.out.println("貓正在移動");
}
public void sleep() {
System.out.println("貓正在睡覺");
}
public void relax() {
System.out.println("貓正在休息");
}
}
Danimal類:
public class Danimal {
public void a1(Eat e){
e.eat();
}
public void a2(Move m){
m.move();
}
public void a3(Sleep s){
s.sleep();
}
}
Canimal類:
class Canimal {
public void b2(Move m){
m.move();
}
public void b3(Sleep s){
s.sleep();
}
public void b4(Relax r){
r.relax();
}
}
測試類:
public class Test {
public static void main(String[] args){
Canimal c = new Canimal();
Cat cat = new Cat();
c.b2(cat);
c.b3(cat);
c.b4(cat);
Danimal d = new Danimal();
Dog dog = new Dog();
d.a1(dog);
d.a2(dog);
d.a3(dog);
}
}
輸出結果:
貓正在移動
貓正在睡覺
貓正在休息
狗正在吃飯
狗正在移動
狗正在睡覺
相關推薦
淺談設計模式的六大原則
一,單一職責原則:就一個類而言,應該僅有一個引起它變化的原因(就是實現類要責任單一) 英文--Single Responsibility Principle 簡寫:SRP 舉個例子: 父類:Animal public class Animal { vo
設計模式六大原則之裏氏替換原則
number -h ole 擁有 method about rect sse 程序 1 裏氏替換原則定義 Liskov於1987年提出了一個關於繼承的原則“Inheritance should ensure that any property proved about su
設計模式--六大原則
活性 tro 開閉 拆分 其中 com att 隔離 裏氏替換原則 設計模式六大原則 單一職責原則: 不要存在多於一個導致類變更的原因。**通俗的說,即一個類只負責一項職責 裏氏替換原則: 裏氏替換原則通俗的來講就是:子類可以擴展父類的功能,但不能改變父
設計模式六大原則(6):開閉原則
思考 外部 編程人員 恰恰 單一職責 何事 適應 擴展 分享 開閉原則 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對
【大話設計模式】——淺談設計模式基礎
表示 無用功 隱式 art -s -m 個人 pri one 初學設計模式給我最大的感受是:人類真是偉大啊!單單是設計模式的基礎課程就讓我感受到了強烈的生活氣息。個人感覺《大話設計模式》這本書寫的真好。讓貌似非常晦澀難懂的設計模式變的生活化。趣味化。 以下淺談一
設計模式六大原則
編程 color 什麽 例子 進行 函數 細節 增加 客戶 1、開閉原則:Open Close Principle 是軟件實體(類,模塊,函數等)應該可以擴展,但是不可修改。 理解:只以基於原本的來擴展功能,但不能修改原本的代碼。已經面對需求時,對程序的改動是通過增加新
11設計模式六大原則——開閉原則
職責 art 並不是 錯誤 接口 屬於 倒置 編程 探討 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對整個功能進行重構,
java設計模式六大原則
設計者 做的 設計模式 員工 打印 temp 有一種 基於 imp 目錄: 設計模式六大原則(1):單一職責原則 設計模式六大原則(2):裏氏替換原則 設計模式六大原則(3):依賴倒置原則 設計模式六大原則(4):接口隔離原則 設計模式六大原則(5):迪米特法則 設計模式六
設計模式六大原則(2):裏氏替換原則
tr1 裏氏替換原則 style tar 裏氏替換 href target 替換 設計模式 XN潮寺贛3PF鋁73瓷Hhttp://weibo.com/p/1005056364252732 壇2偈6v實8uka誆敲wmhttp://weibo.com/p/10050563
設計模式六大原則(轉)
method 過多 這樣的 不同 提高 依賴倒置 同心圓 23種設計模式 變化 設計模式六大原則(1):單一職責原則 定義:不要存在多於一個導致類變更的原因。通俗的說,即一個類只負責一項職責。 問題由來:類T負責兩個不同的職責:職責P1,職責P2。當由於職責P1需求發
設計模式六大原則(一):單一職責原則
控制 line 避免 多人 由來 pan 兩個類 思想 功能 單一職責定義: 不要存在多於一個導致類變更的原因,通俗的說,即一個類只負責一項職責。 問題由來: 類T負責兩個不同的職責:職責P1,職責P2。當由於職責P1需求發生改變而需要修改類T時,有可能會導致原
設計模式六大原則(4):接口隔離原則
說明 兩個 復雜 試圖 所有 類圖 系統 客戶端 face 定義:客戶端不應該依賴它不需要的接口;一個類對另一個類的依賴應該建立在最小的接口上。 問題由來:類A通過接口I依賴類B,類C通過接口I依賴類D,如果接口I對於類A和類B來說不是最小接口,則類B和類D必須去實現他
[轉]設計模式六大原則[5]:迪米特法則
順序分配 intall 其他 過程 封裝 this 模塊 修改 最好 定義:一個對象應該對其他對象保持最少的了解。 問題由來:類與類之間的關系越密切,耦合度越大,當一個類發生改變時,對另一個類的影響也越大。 解決方案:盡量降低類與類之間的耦合。 自從我們接觸編程開
[轉]設計模式六大原則[6]:開閉原則
說了 一點 模塊 活性 問題 單一職責原則 就是 認識 適應 定義:一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉。 問題由來:在軟件的生命周期內,因為變化、升級和維護等原因需要對軟件原有代碼進行修改時,可能會給舊代碼中引入錯誤,也可能會使我們不得不對整個功能進行
[轉]設計模式六大原則[4]:接口隔離原則
職責 活性 六大原則 方案 朋友 oid 專用 出現 即使 定義:客戶端不應該依賴它不需要的接口;一個類對另一個類的依賴應該建立在最小的接口上。 問題由來:類A通過接口I依賴類B,類C通過接口I依賴類D,如果接口I對於類A和類B來說不是最小接口,則類B和類D必須去實現他們
Java設計模式六大原則或者說七大原則
設計 sub 隔離 single lose 開閉原則 bili div 依賴倒轉原則 1.開閉原則(Open Close Principle) 2.裏氏代換原則(Liskov Substitution Principle) 3.依賴倒轉原則(Dependence Inver
(讓BAT的Offer不再難拿)淺談設計模式在iOS開發實戰項目中的應用
設計模式的 簡化 情況 結合 在線 百度 是個 開發 方案 在我們日常的開發中設計模式伴隨著項目的各個模塊,巧妙地使用設計模式可以讓我們寫出更高效,簡潔,優美的代碼。可是因為對於設計模式的不熟悉,很多高效的設計模式並沒有被很好地使用起來,現在包括曾經寫的一些代碼,然後在優化
設計模式-六大原則
改變 開閉 目的 但是 了解 關閉 軟件 設計 模塊 一,單一職責原則 不要存在多於一個導致類變更的原因。 二,裏氏代換原則 子類可以擴展父類的功能,但是不能改變父類原有的功能。 三,依賴倒置原則 高層模塊不應該依賴底層模塊,二者都應該依賴其抽象了;抽象不依賴細節;細節應該
面試寶典-設計模式六大原則
面試 軟件 負責 面向 可維護性 迪米特法則 接口隔離原則 定義 輸入 1、單一職責原則 定義:不要存在多於一個導致類變更的原因。通俗的說,即一個類只負責一項職責。 遵循單一職責原的優點有: 可以降低類的復雜度,一個類只負責一項職責,其邏輯肯定要比負責多項職責簡單的多
JAVA23種設計模式六大原則,資料結構演算法強化訓練
目錄: 設計模式六大原則(1):單一職責原則 設計模式六大原則(2):里氏替換原則 設計模式六大原則(3):依賴倒置原則 設計模式六大原則(4):介面隔離原則 設計模式六大原則(5):迪米特法則 設計模式六大原則(6):開閉原則 設計模式六大原則(1):單一職責原則 定義:不要存在多於一個導致