設計模式學習
做了幾個項目,發現設計模式的好處還是很多的,這東西就是隻有你真正用到的時候才知道他的好處,否則學了也不知道所以然。所以設計模式學習我認爲可以在先進行幾個項目後,再來學習,這樣學習的效果和感受纔是最好的。
這次是做一個學習的筆記,內容還是主要以我看的兩本書《大話設計模式》、《head first 設計模式》,以及我在網上找到的一些內容爲主,還有就是附帶的一些自己的感悟(這些有可能是有問題的,還會再改,所以大家要是看一定要有分辨地去看)。主要還是覺得做一個學習的筆記可能會是我堅持下去的動力。
設計模式的類型
下面這是從菜鳥教程上面摘的,感覺不錯就拿下來了,http://www.runoob.com/design-pattern/design-pattern-intro.html
創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
這些設計模式提供了一種在創建對象的同時隱藏創建邏輯的方式,而不是使用 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 廠商是個父類,有生產鼠標,生產鍵盤兩個接口。
戴爾工廠,惠普工廠繼承它,可以分別生產戴爾鼠標+戴爾鍵盤,和惠普鼠標+惠普鍵盤。
創建工廠時,由戴爾工廠創建。
後續工廠.生產鼠標()則生產戴爾鼠標,工廠.生產鍵盤()則生產戴爾鍵盤。
/**
* @ClassName: Mouse
* @Description: Mouse接口類
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:36
*/
public interface Mouse {
public void sayHi();
}
/**
* @ClassName: DellMouse
* @Description: java類作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:39
*/
public class DellMouse implements Mouse{
public void sayHi(){
System.out.println("produce DellMouse");
}
}
/**
* @ClassName: HpMouse
* @Description: mouse接口實體類
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:40
*/
public class HpMouse implements Mouse{
public void sayHi(){
System.out.println("produce HpMouse");
}
}
/**
* @ClassName: Keybo
* @Description: java類作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:42
*/
public interface Keybo {
public void sayHi();
}
/**
* @ClassName: DellKeybo
* @Description: java類作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:43
*/
public class DellKeybo implements Keybo{
public void sayHi(){
System.out.println("produce DellKeybo");
}
}
/**
* @ClassName: HpKeybo
* @Description: java類作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:44
*/
public class HpKeybo implements Keybo{
public void sayHi(){
System.out.println("produce HpKeybo");
}
}
/**
* @ClassName: PcFactory
* @Description: 工廠類接口
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:45
*/
public interface PcFactory {
public Mouse createMouse();
public Keybo createKeybo();
}
/**
* @ClassName: DellFactory
* @Description: java類作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:46
*/
public class DellFactory implements PcFactory{
@Override
public Mouse createMouse() {
return new DellMouse();
}
@Override
public Keybo createKeybo() {
return new DellKeybo();
}
}
/**
* @ClassName: HpFactory
* @Description: java類作用描述
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:48
*/
public class HpFactory implements PcFactory{
@Override
public Mouse createMouse() {
return new HpMouse();
}
@Override
public Keybo createKeybo() {
return new HpKeybo();
}
}
/**
* @ClassName: AbstractFactoryPatternTest1
* @Description: 測試類
* @Author: xinyuan
* @CreateDate: 2018/9/24 9:50
*/
public class AbstractFactoryPatternTest1 {
public static void main(String[] args){
PcFactory pcFactory = new DellFactory();
Keybo keybo = pcFactory.createKeybo();
keybo.sayHi();
Mouse mouse = pcFactory.createMouse();
mouse.sayHi();
PcFactory pcFactory1 = new HpFactory();
Keybo keybo1 = pcFactory1.createKeybo();
keybo1.sayHi();
Mouse mouse1 = pcFactory1.createMouse();
mouse1.sayHi();
}
}
在抽象工廠模式中,假設我們需要增加一個工廠
假設我們增加華碩工廠,則我們需要增加華碩工廠,和戴爾工廠一樣,繼承 PC 廠商。
之後創建華碩鼠標,繼承鼠標類。創建華碩鍵盤,繼承鍵盤類即可。
在抽象工廠模式中,假設我們需要增加一個產品
假設我們增加耳麥這個產品,則首先我們需要增加耳麥這個父類,再加上戴爾耳麥,惠普耳麥這兩個子類。
之後在PC廠商這個父類中,增加生產耳麥的接口。最後在戴爾工廠,惠普工廠這兩個類中,分別實現生產戴爾耳麥,惠普耳麥的功能。 以上。