設計模式學習總結(1)簡單工廠模式、工廠方法模式、抽象工廠模式
設計模式學習
做了幾個專案,發現設計模式的好處還是很多的,這東西就是隻有你真正用到的時候才知道他的好處,否則學了也不知道所以然。所以設計模式學習我認為可以在先進行幾個專案後,再來學習,這樣學習的效果和感受才是最好的。
這次是做一個學習的筆記,內容還是主要以我看的兩本書《大話設計模式》、《head first 設計模式》,以及我在網上找到的一些內容為主,還有就是附帶的一些自己的感悟(這些有可能是有問題的,還會再改,所以大家要是看一定要有分辨地去看)。主要還是覺得做一個學習的筆記可能會是我堅持下去的動力。
設計模式的型別
建立型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
這些設計模式提供了一種在建立物件的同時隱藏建立邏輯的方式,而不是使用 new 運算子直接例項化物件。這使得程式在判斷針對某個給定例項需要建立哪些物件時更加靈活。
結構型模式,共七種:介面卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
這些設計模式關注類和物件的組合。繼承的概念被用來組合介面和定義組合物件獲得新功能的方式。
行為型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式。
這些設計模式特別關注物件之間的通訊。
下面是設計模式的一張關係圖
設計模式的六大原則
1、開閉原則(Open Close Principle)
開閉原則的意思是:對擴充套件開放,對修改關閉。在程式需要進行拓展的時候,不能去修改原有的程式碼,實現一個熱插拔的效果。簡言之,是為了使程式的擴充套件性好,易於維護和升級。想要達到這樣的效果,我們需要使用介面和抽象類,後面的具體設計中我們會提到這點。
2、里氏代換原則(Liskov Substitution Principle)
里氏代換原則是面向物件設計的基本原則之一。 里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現。LSP 是繼承複用的基石,只有當派生類可以替換掉基類,且軟體單位的功能不受到影響時,基類才能真正被複用,而派生類也能夠在基類的基礎上增加新的行為。里氏代換原則是對開閉原則的補充。實現開閉原則的關鍵步驟就是抽象化,而基類與子類的繼承關係就是抽象化的具體實現,所以里氏代換原則是對實現抽象化的具體步驟的規範。
3、依賴倒轉原則(Dependence Inversion Principle)
這個原則是開閉原則的基礎,具體內容:針對介面程式設計,依賴於抽象而不依賴於具體。
4、介面隔離原則(Interface Segregation Principle)
這個原則的意思是:使用多個隔離的介面,比使用單個介面要好。它還有另外一個意思是:降低類之間的耦合度。由此可見,其實設計模式就是從大型軟體架構出發、便於升級和維護的軟體設計思想,它強調降低依賴,降低耦合。
5、迪米特法則,又稱最少知道原則(Demeter Principle)
最少知道原則是指:一個實體應當儘量少地與其他實體之間發生相互作用,使得系統功能模組相對獨立。
6、合成複用原則(Composite Reuse Principle)
合成複用原則是指:儘量使用合成/聚合的方式,而不是使用繼承。
1、工廠模式
簡單工廠模式(simple Factory)
簡單工廠模式不屬於23種設計模式中的一種,簡單工廠一般分為:普通簡單工廠、多方法簡單工廠、靜態方法簡單工廠。就是有一個專門生產某個產品的類
在簡單工廠模式中,一個工廠類處於對產品類例項化呼叫的中心位置上,它決定那一個產品類應當被例項化, 如同一個交通警察站在來往的車輛流中,決定放行那一個方向的車輛向那一個方向流動一樣。
01普通
介面shape類
/**
* 簡單工廠模式
* 建立一個介面
* shape類:實現介面
*/
public interface shape {
void draw();
}
介面實現實體類:Circle類、Rectangle
public class Circle implements shape{
@Override
public void draw(){
System.out.println("draw a circle");
}
}
/**
* 簡單工廠模式
* 建立一個實現介面的實體類
* Rectangle畫一個矩形
*/
public class Rectangle implements shape{
@Override
public void draw(){
System.out.println("draw a Rectangle");
}
}
工廠類
/**
* 簡單工廠模式
* 建立一個工廠,生成基於給定資訊的實體類的物件
* 2018/9/23 15:40
*/
public class ShapeFactory {
//使用一個getShape方法獲取形狀型別物件
public shape getShape(String shapeType){
if(shapeType == null){
System.out.println("please enter right word:");
}else if(shapeType.equals("circle")){
return new Circle();
}else if(shapeType.equals("rectangle")){
return new Rectangle();
}
return null;
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: SimpleFactoryPatternTest
* @Description: 簡單工廠模式,用於進行測試
* @Author: xinyuan
* @CreateDate: 2018/9/23 15:48
*/
public class SimpleFactoryPatternTest {
public static void main(String[] args){
ShapeFactory shapeFactory = new ShapeFactory();
//獲取Circle物件,並呼叫它的draw方法
shape shape1 = shapeFactory.getShape("circle");
shape1.draw();
//獲取Rectangle物件,並呼叫它的draw方法
shape shape2 = shapeFactory.getShape("rectangle");
shape2.draw();
}
}
測試結果:
draw a circle
draw a Rectangle
Process finished with exit code 0
02多個方法
工廠類和測試類發生改變,其餘不變
/**
* @ProjectName: Factory_Pattern
* @ClassName: ShapeFactory1
* @Description: 多個方法的簡單工廠模式的工廠類
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:06
*/
public class ShapeFactory1 {
public shape drawCircle(){
return new Circle();
}
public shape drawRectangle(){
return new Rectangle();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: SimpleFactoryPatternTest1
* @Description: 多個方法的簡單工廠模式,用於進行測試
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:10
*/
public class SimpleFactoryPatternTest1 {
public static void main(String[] args){
ShapeFactory1 shapeFactory1 = new ShapeFactory1();
//獲取Circle物件,並呼叫它的draw方法
shape shape1 = shapeFactory1.drawCircle();
shape1.draw();
//獲取Rectangle物件,並呼叫它的draw方法
shape shape2 = shapeFactory1.drawRectangle();
shape2.draw();
}
}
測試結果同上,就不放了。。。
03 多個靜態方法
將工廠裡的方法設定為靜態的,這樣在main裡就可以不建立實體直接呼叫。
/**
* @ProjectName: Factory_Pattern
* @ClassName: ShapeFactory2
* @Description: 多個靜態方法的簡單工廠模式的工廠類
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:17
*/
public class ShapeFactory2 {
public static shape drawCircle(){
return new Circle();
}
public static shape drawRectangle(){
return new Rectangle();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: SimpleFactoryPatternTest2
* @Description: 多個靜態方法的簡單工廠模式的測試類
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:19
*/
public class SimpleFactoryPatternTest2 {
public static void main(String[] args){
shape circle = ShapeFactory2.drawCircle();
circle.draw();
shape rectangle = ShapeFactory2.drawRectangle();
rectangle.draw();
}
}
測試結果同上。。。
2、工廠方法模式(Factory Method)
簡單工廠模式有一個問題就是,類的建立依賴工廠類,也就是說,如果想要拓展程式,必須對工廠類進行修改,這違背了閉包原則,所以,從設計角度考慮,有一定的問題,如何解決?就用到工廠方法模式,建立一個工廠介面和建立多個工廠實現類,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的程式碼。(給工廠也建立一個相應的介面,這樣就好拓展了)
/**
* @ProjectName: Factory_Pattern
* @ClassName: ShapeFactory
* @Description: 工廠類的介面
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:43
*/
public interface ShapeFactory {
public shape drawShape();
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: DrawCircleFactory
* @Description: 工廠方法模式,工廠實體類
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:45
*/
public class DrawCircleFactory implements ShapeFactory{
@Override
public shape drawShape(){
return new Circle();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: DrawRectangleFactory
* @Description: 工廠方法模式,工廠實體類
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:46
*/
public class DrawRectangleFactory implements ShapeFactory{
public shape drawShape(){
return new Rectangle();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: FactoryPatternTest
* @Description: 工廠方法模式測試類
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:47
*/
public class FactoryPatternTest {
public static void main(String[] args){
ShapeFactory shapeFactory = new DrawCircleFactory();
shape circle = shapeFactory.drawShape();
circle.draw();
ShapeFactory shapeFactory1 = new DrawRectangleFactory();
shape rectangle = shapeFactory1.drawShape();
rectangle.draw();
}
}
3、抽象工廠方法
工廠方法模式: 一個抽象產品類,可以派生出多個具體產品類。 一個抽象工廠類,可以派生出多個具體工廠類。 每個具體工廠類只能建立一個具體產品類的例項。 抽象工廠模式: 多個抽象產品類,每個抽象產品類可以派生出多個具體產品類。 一個抽象工廠類,可以派生出多個具體工廠類。 每個具體工廠類可以建立多個具體產品類的例項,也就是建立的是一個產品線下的多個產品。 區別: 工廠方法模式只有一個抽象產品類,而抽象工廠模式有多個。 工廠方法模式的具體工廠類只能建立一個具體產品類的例項,而抽象工廠模式可以建立多個。
工廠方法建立 "一種" 產品,他的著重點在於"怎麼建立",也就是說如果你開發,你的大量程式碼很可能圍繞著這種產品的構造,初始化這些細節上面。也因為如此,類似的產品之間有很多可以複用的特徵,所以會和模版方法相隨。 抽象工廠需要建立一些列產品,著重點在於"建立哪些"產品上,也就是說,如果你開發,你的主要任務是劃分不同差異的產品線,並且儘量保持每條產品線介面一致,從而可以從同一個抽象工廠繼承。
對於java來說,你能見到的大部分抽象工廠模式都是這樣的: ---它的裡面是一堆工廠方法,每個工廠方法返回某種型別的物件。 比如說工廠可以生產滑鼠和鍵盤。那麼抽象工廠的實現類(它的某個具體子類)的物件都可以生產滑鼠和鍵盤,但可能工廠A生產的是羅技的鍵盤和滑鼠,工廠B是微軟的。 這樣A和B就是工廠,對應於抽象工廠; 每個工廠生產的滑鼠和鍵盤就是產品,對應於工廠方法; 用了工廠方法模式,你替換生成鍵盤的工廠方法,就可以把鍵盤從羅技換到微軟。但是用了抽象工廠模式,你只要換家工廠,就可以同時替換滑鼠和鍵盤一套。如果你要的產品有幾十個,當然用抽象工廠模式一次替換全部最方便(這個工廠會替你用相應的工廠方法) 所以說抽象工廠就像工廠,而工廠方法則像是工廠的一種產品生產線
/**
* @ProjectName: Factory_Pattern
* @ClassName: Color
* @Description: 抽象工廠模式
* @Author: xinyuan
* @CreateDate: 2018/9/23 17:17
*/
public interface Color {
public void fill();
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: Red
* @Description: 抽象工廠模式,color介面的實體類
* @Author: xinyuan
* @CreateDate: 2018/9/23 17:18
*/
public class Red implements Color{
@Override
public void fill(){
System.out.println("color is red");
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: Blue
* @Description: 抽象工廠模式,color介面的實體類
* @Author: xinyuan
* @CreateDate: 2018/9/23 17:20
*/
public class Blue implements Color{
public void fill(){
System.out.println("color is blue");
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: DrawBlueFactory
* @Description: java類作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/23 17:30
*/
public class DrawBlueFactory implements ShapeFactory{
@Override
public shape drawShape(){
return null;
}
@Override
public Color drawColor(){
return new Blue();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: DrawRedFactory
* @Description: java類作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/23 17:25
*/
public class DrawRedFactory implements ShapeFactory{
@Override
public shape drawShape(){
return null;
}
@Override
public Color drawColor(){
return new Red();
}
}
/**
* @ProjectName: Factory_Pattern
* @ClassName: FactoryPatternTest
* @Description: 工廠方法模式測試類
* @Author: xinyuan
* @CreateDate: 2018/9/23 16:47
*/
public class FactoryPatternTest {
public static void main(String[] args){
ShapeFactory shapeFactory = new DrawCircleFactory();
shape circle = shapeFactory.drawShape();
circle.draw();
ShapeFactory shapeFactory1 = new DrawRectangleFactory();
shape rectangle = shapeFactory1.drawShape();
rectangle.draw();
ShapeFactory shapeFactory2 = new DrawRedFactory();
Color red = shapeFactory2.drawColor();
red.fill();
ShapeFactory shapeFactory3 = new DrawBlueFactory();
Color blue = shapeFactory3.drawColor();
blue.fill();
}
}
下面的這些是從菜鳥教程上找的,感覺總結的挺好的,就拿下來看看,這樣也好以後複習。
下面例子中滑鼠,鍵盤,耳麥為產品,惠普,戴爾為工廠。
簡單工廠模式
簡單工廠模式不是 23 種裡的一種,簡而言之,就是有一個專門生產某個產品的類。
比如下圖中的滑鼠工廠,專業生產滑鼠,給引數 0,生產戴爾滑鼠,給引數 1,生產惠普滑鼠。
工廠模式
工廠模式也就是滑鼠工廠是個父類,有生產滑鼠這個介面。
戴爾滑鼠工廠,惠普滑鼠工廠繼承它,可以分別生產戴爾滑鼠,惠普滑鼠。
生產哪種滑鼠不再由引數決定,而是建立滑鼠工廠時,由戴爾滑鼠工廠建立。
後續直接呼叫滑鼠工廠.生產滑鼠()即可
抽象工廠模式
抽象工廠模式也就是不僅生產滑鼠,同時生產鍵盤。
也就是 PC 廠商是個父類,有生產滑鼠,生產鍵盤兩個介面。
戴爾工廠,惠普工廠繼承它,可以分別生產戴爾滑鼠+戴爾鍵盤,和惠普滑鼠+惠普鍵盤。
建立工廠時,由戴爾工廠建立。
後續工廠.生產滑鼠()則生產戴爾滑鼠,工廠.生產鍵盤()則生產戴爾鍵盤。
在抽象工廠模式中,假設我們需要增加一個工廠
假設我們增加華碩工廠,則我們需要增加華碩工廠,和戴爾工廠一樣,繼承 PC 廠商。
之後建立華碩滑鼠,繼承滑鼠類。建立華碩鍵盤,繼承鍵盤類即可。
在抽象工廠模式中,假設我們需要增加一個產品
假設我們增加耳麥這個產品,則首先我們需要增加耳麥這個父類,再加上戴爾耳麥,惠普耳麥這兩個子類。
之後在PC廠商這個父類中,增加生產耳麥的介面。最後在戴爾工廠,惠普工廠這兩個類中,分別實現生產戴爾耳麥,惠普耳麥的功能。 以上。