java详细设计模式有代码
文章目錄
- 設計模式
- 1.七大原則
- 1.單一職責原則
- 2.接口隔離原則
- 3.依賴倒轉原則
- 代碼實現
- 有問題代碼
- 實現依賴倒轉原則以后的代碼
- 4.里氏替換原則
- 5.開閉原則
- 6.迪米特法原則
- **7.合成復用原則**
- 設計模式:
- 1.單例模式:
- 餓漢模式:
- 懶漢模式(雙重if判斷):
- 懶漢模式靜態(tài)內部類:
- 枚舉單例模式:
- 2.策略模式(把相同行為的不同實現進行封裝)
- 3. 享元模式(Flyweight pattern)
- 4.代理模式
- 靜態(tài)代理
- 動態(tài)代理(JDK代理)
- cglib代理
- 5.模板方法模式
- 6.觀察者模式
- 7.工廠模式
- 7.1代碼
- 7.2抽象出來的三個抽象類
- 7.3 把三個抽象類放到一個抽象類中封裝
- 7.4 每個產品增加自己產品抽象類,繼承(extends)抽象父類
- 7.41現代世界的人
- 7.42魔法世界的人
- 7.43客戶端進行調用,修改MagicStickFactory這個產品就可以進行不同的調用
設計模式
1.七大原則
1.單一職責原則
(每個類或者每個方法只需要實現一個職責,不需要實現很多其他的功能。)在類中的方法足夠多需要在類的層面遵守單一職責原則
方法遵循單一職責代碼實現:
package com.example;public class SingleResponsibility {public static void main(String[] args) {Vehicle vehicle = new Vehicle();vehicle.runAir("飛機");vehicle.runRolad("車子");vehicle.runWater("游艇");} } class Vehicle{public void runRolad(String vehicle){System.out.println(vehicle + "在公路上面運行");}public void runWater(String vehicle){System.out.println(vehicle + "在水中上面運行");}public void runAir(String vehicle){System.out.println(vehicle + "在天上運行");} }2.接口隔離原則
A通過接口B依賴于C(只要實現接口B的1,2,3方法),D通過接口B依賴于F(只需要 實現接口B的1,4,5方法),這樣A就得實現所有的B接口的方法,D就得實現所有的B接口方法,導致浪費,且相關性強,所以得遵循接口最小原則,把 方法1 放在一個接口Interface1, 方法 2,3放在一個接口Interface2 ,方法4,5放在一個接口Interface3.
3.依賴倒轉原則
代碼實現
有問題代碼
package com.monkey.single.inversion;public class DependenceInversion {public static void main(String[] args) {Person person = new Person();person.receiveMessage(new Email());} }class Email{public String getInfo(){return "email,helloWorld";} }//1.這個只可以接收郵箱的消息,不可以接收其他的比如微信,支付寶,短信的消息。 //2.我們可以來創(chuàng)建一個接口IReceiver(),這樣Person類和接口IReceiver發(fā)生依賴 //因為Email,WeChat等等屬于接收的范圍,他們各自實現IReceiver接口就行,這樣就發(fā)生了依賴倒轉。class Person{ // 這里是對實現類進行了依賴public void receiveMessage(Email email){System.out.println(email.getInfo());}}實現依賴倒轉原則以后的代碼
package com.monkey.single.inversion;public class DependenceInversion {public static void main(String[] args) {Person person = new Person();person.receiveMessage(new Email());person.receiveMessage(new Wexin());} }interface Ireceiver{public String getInfo(); }class Email implements Ireceiver{public String getInfo(){return "email,helloWorld";} }class Wexin implements Ireceiver{public String getInfo(){return "wexin,helloWorld";}}//1.這個只可以接收郵箱的消息,不可以接收其他的比如微信,支付寶,短信的消息。 //2.我們可以來創(chuàng)建一個接口IReceiver(),這樣Person類和接口IReceiver發(fā)生依賴 //因為Email,WeChat等等屬于接收的范圍,他們各自實現IReceiver接口就行,這樣就發(fā)生了依賴倒轉。class Person{// 這里是對接口進行依賴,穩(wěn)定性好public void receiveMessage(Ireceiver ireceiver){System.out.println(ireceiver.getInfo());}}實現接口間依賴傳遞的三種方式:
代碼:
4.里氏替換原則
5.開閉原則
6.迪米特法原則
7.合成復用原則
經典面試題目?
在項目的實際開發(fā)中哪里使用了ocp原則? (工廠模式中有用)
spring中應用了哪些設計模式,原型模式在哪里 用到?
什么是解釋器設計模式?畫出它的UML類圖,分析各個角色是什么?
spring框架中哪里使用到了解釋器設計模式?并做源碼級別分析
單例模式一共有幾種實現方式?用代碼實現,并說明各個的優(yōu)點缺點。
單列設計模式有幾種實現方式?
餓漢式 兩種
懶漢式 三種
雙重檢查
靜態(tài)內部類
設計模式概念:(design pattern)是對在軟件設計普遍存在(反復出現)的各種問題,提出 的一種解決方案。
使用設計模式可以使用項目具有:可擴展性,維護性,可靠性(新增一個功能對原來的功能影響不大),可復用性,效率提高等等
設計模式:
1.單例模式:
餓漢模式:
package com.monkey.sigleton; /* * 餓漢模式: * 類加載就實例化,JVM保證線程安全 * 推薦使用 * 唯一缺點: 不管使用與與否,類加載就會完成實例化 * * */ public class HungryMode {private static final HungryMode Instance = new HungryMode();private HungryMode(){};public static HungryMode getInstance(){return Instance;}public static void main(String[] args) {HungryMode instance = HungryMode.getInstance();HungryMode instance1 = HungryMode.getInstance();System.out.println(instance == instance1);}}懶漢模式(雙重if判斷):
package com.monkey.sigleton;public class LazyModeImprove {private static LazyModeImprove Instance;private LazyModeImprove(){};private static LazyModeImprove getInstance(){if(Instance == null){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (LazyModeImprove.class){if(Instance == null){Instance = new LazyModeImprove();}}}return Instance;}public static void main(String[] args) {for (int i = 0; i < 1000; i++) {new Thread(()->System.out.println(Instance.getInstance())).start();}} }懶漢模式靜態(tài)內部類:
package com.monkey.sigleton;public class LazyModeStaicInnerClass {private LazyModeStaicInnerClass(){};private static class SingletonInstance{private static final LazyModeStaicInnerClass Instance = new LazyModeStaicInnerClass();}public static LazyModeStaicInnerClass getInstance(){return SingletonInstance.Instance;}}枚舉單例模式:
package com.monkey.sigleton;public enum EnumMode{ // 1. 可以防止反序列化,也是線程安全的INSTANCE;public void hellowWord(){System.out.println("hello Word");}public static void main(String[] args) {INSTANCE.hellowWord();}}2.策略模式(把相同行為的不同實現進行封裝)
package com.monkey.strategy.improve;public abstract class Duck {FlyBehavior flyBehavior;public Duck() {}public abstract void display();//顯示鴨子信息public void setFlyBehavior(FlyBehavior flyBehavior) {this.flyBehavior = flyBehavior;}public void quack(){System.out.println("鴨子會嘎嘎叫");}public void swim(){System.out.println("鴨子會游戲");} // public void fly(){ // System.out.println("鴨子會飛行"); // } // improvepublic void fly(){if(flyBehavior !=null){flyBehavior.fly();}} } package com.monkey.strategy.improve;public interface FlyBehavior {void fly(); //子類具體實現 } package com.monkey.strategy.improve;public class GoodFlyBehavior implements FlyBehavior{@Overridepublic void fly() {System.out.println("飛翔技術高超");} } package com.monkey.strategy.improve;public class GoodFlyBehavior implements FlyBehavior{@Overridepublic void fly() {System.out.println("飛翔技術高超");} } package com.monkey.strategy.improve;public class PekingDuck extends Duck {PekingDuck(){flyBehavior = new BadFlyBehavior();}@Overridepublic void display() {System.out.println("我是北京鴨");} //北京鴨不能飛行,這里需要重寫方法/* @Overridepublic void fly() {System.out.println("北京鴨不能飛行");}*/ } package com.monkey.strategy.improve;public class ToyDuck extends Duck {ToyDuck(){flyBehavior = new BadFlyBehavior();}@Overridepublic void display() {System.out.println("我是玩具鴨");} // 需要重寫父類的所有方法public void quack(){System.out.println("玩具鴨子不會嘎嘎叫"); }public void swim(){System.out.println("玩具鴨子不會游戲");} // public void fly(){ // System.out.println("玩具鴨子不會飛行"); // } } package com.monkey.strategy.improve;public class WildDuck extends Duck {WildDuck(){flyBehavior = new GoodFlyBehavior();}@Overridepublic void display() {System.out.println("我是野鴨子");} }3. 享元模式(Flyweight pattern)
場景應用:**數據庫連接池,緩沖池,Integer的底層源碼,String常量池等等。**可以解決重復對象內存浪費問題。
理解:需要的我們拿來使用,不需要的直接創(chuàng)建 new一個。
String str = "hello"; String s2 = new String("hello ");**內部狀態(tài):**對象共享出來的信息,且不隨享元對象的外部狀態(tài)改變而改變。
**外部狀態(tài):**隨環(huán)境的改變而改變,不可共享的一個狀態(tài)。
public class IntegerCode {public static void main(String[] args) {Integer integer = Integer.valueOf(126);Integer integer1 = Integer.valueOf(126);System.out.println(integer == integer1);Integer integer2 = Integer.valueOf(128);Integer integer3 = Integer.valueOf(128);System.out.println(integer2 == integer3);} } //里面的Integer.valueOf()使用了享元模式,如果大小在[-128,127]之間使用同一個數組里面的數據,否則重新創(chuàng)建一個Integer類型對象,減少了內存的消耗。4.代理模式
為一個對象提供一個替身,以控制這個對象的訪問。即 通過代理對象訪問目標對象。
被代理的對象可以是 遠程對象,創(chuàng)建開銷大的對象,或需要安全控制的對象。
主要有:動態(tài)代理(也叫jdk代理),靜態(tài)代理,cglib代理(可以在內存動態(tài)的創(chuàng)建對象,不需要實現接口,屬于動態(tài)代理)。
在有些情況下,我們不可以直接訪問目標對象,需要通過另外一個對象進行代理訪問。
靜態(tài)代理
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-owrRldFi-1659411175436)(C:\Users\24473\AppData\Roaming\Typora\typora-user-images\image-20220706230151861.png)]
動態(tài)代理(JDK代理)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ludHQFDo-1659411175438)(C:\Users\24473\AppData\Roaming\Typora\typora-user-images\image-20220709173609450.png)]
圖片上面是復用反射機制
可以看到代理對象不用實現目標接口
其實是通過 java的反射機制實現,然后通過代理對象進行調用ITeacherDao方法。
代理對象=增強內容+原對象。 其實就是spring中的aop我們想在當前的業(yè)務邏輯下添加一些其他的處理,比如日志、校驗等等,就不得不侵入原有的業(yè)務代碼,尤其是在重重繼承關系復雜的類中,需要增加一些內容,并不清楚會不會影響到其他功能,所以使用代理來實現需要增加的內容 package com.monkey.proxy.dynamic;public interface IteacherDao {void teach();//String sayProxyStart(String proxyName); } package com.monkey.proxy.dynamic;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;public class ProxyFactory {private Object target; //代理的目標對象// 有參樹構造器,對target 進行初始化public ProxyFactory(Object target) {this.target = target;}//給目標對象通過 JDK的API 生成代理對象的方法public Object getProxyInstace(){ // ClassLoader loader 類加載器 // 2. Class<?> interface // 3. InvocationHandler //return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("jdk動態(tài)代理開始");Object object = method.invoke(target, args);return object;}});} } package com.monkey.proxy.dynamic;import com.monkey.proxy.ITeacherDao;public class Teacher implements IteacherDao {@Overridepublic void teach() {System.out.println("老師正在授課中。。。。。。。。。。");}@Overridepublic String sayProxyStart(String proxyName) {return proxyName;}} package com.monkey.proxy.dynamic;public class Client {public static void main(String[] args) {Teacher target = new Teacher();// 需要強制類型轉換為ITeacherDao才可以調用到 接口里面的方法IteacherDao proxyInstace = (IteacherDao)new ProxyFactory(target).getProxyInstace();System.out.println("proxyInstace"+proxyInstace); // 調用代理對象的方法proxyInstace.teach();String hello_proxy = proxyInstace.sayProxyStart("hello Proxy");System.out.println(hello_proxy);} }cglib代理
靜態(tài)代理類和jdk代理都需要我們的目標對象實現一個接口,但是有些時候我們希望這個目標對象沒有實現接口,可以使用目標對象的子類實現代理,這就是cglib代理。
cglib是一個強大的,高性能的代碼生成包,它可以在運行期擴展java類實現java接口,(SpringAop中有使用,實現方法攔截。)
在Aop編程中如何選用代理模式:
cglib底層是使用字節(jié)碼處理框架ASM,轉換字節(jié)碼,并生成新的類。
ProxyFactory(代理對象需要 implements MethodInterceptor) MethodInterceptor是框架待的一個接口方法攔截,里面重寫了 interceptor方法
5.模板方法模式
在一個抽象類中公開定義了一個執(zhí)行它的方法模板,它的子類可以進行重寫(關鍵的步驟)方法來實現,但調用將以抽象類中定義的方式進行。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ISCrvslB-1659411189861)(C:\Users\24473\AppData\Roaming\Typora\typora-user-images\image-20220714230054147.png)]
重點
代碼實現:
package com.monkey.template;public abstract class SoyaMilk { // 制作豆?jié){模板final void make(){select();if(customerAddCondiments()){addCondiments();}soak();beat();}//選材料void select(){System.out.println("第一步,選擇好新鮮的黃豆");}//添加不同的配料,抽象方法,子類具體實現abstract void addCondiments();boolean customerAddCondiments(){return true;}//浸泡void soak(){System.out.println("第三步,黃豆進行浸泡");}void beat(){System.out.println("第四步,黃豆打碎");} } package com.monkey.template;public class RedBeanSoyaMilck extends SoyaMilk{@Overridevoid addCondiments() {System.out.println("加入上好的紅豆豆?jié){");} } package com.monkey.template;public class PureSoyaMilk extends SoyaMilk{@Overridevoid addCondiments() {//純的豆?jié){不用添加}@Overrideboolean customerAddCondiments() {//因為是純的豆?jié){不用添加任何其他的東西return false;} } package com.monkey.template;public class PeanutSoyaMilk extends SoyaMilk{@Overridevoid addCondiments() {System.out.println("加入上好的花生豆?jié){");} } package com.monkey.template;public class Client {public static void main(String[] args) {System.out.println("紅豆豆?jié){開始制作");SoyaMilk soyaMilk = new RedBeanSoyaMilck();soyaMilk.make();System.out.println("花生豆?jié){開始制作");SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();peanutSoyaMilk.make();System.out.println("純豆?jié){開始制作");SoyaMilk pureSoyaMilk = new PureSoyaMilk();pureSoyaMilk.make();} }6.觀察者模式
又叫發(fā)布-訂閱模式,模型視圖模式, 從屬模式, 源-監(jiān)聽模式。
概念:**定義了一對多的依賴關系,讓多個觀察者同時監(jiān)聽某個主題對象。**主題對象在狀態(tài)上發(fā)生變化,會同時通知所有觀察者對象,使他們同時更新自己。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-sIalrkBc-1659411203154)(C:\Users\24473\AppData\Roaming\Typora\typora-user-images\image-20220722222223344.png)]
改進觀察者好處:
JDK源碼中有一個ObServable類實現了觀察者模式
在這里相當于 Subject這個接口,進行管理Observer
Observable,里面的addObserver,deleteObserve,notifyObserver分別對應Subject里面的相關的方法。
Observer作用等價于我們的Observer,里面也有update方法。
只是源碼是通過繼承實現的,Observable里面已經實現了相關的方法實現
public class Observable {private boolean changed = false;private Vector<Observer> obs;/** Construct an Observable with zero Observers. */public Observable() {obs = new Vector<>();}/*** Adds an observer to the set of observers for this object, provided* that it is not the same as some observer already in the set.* The order in which notifications will be delivered to multiple* observers is not specified. See the class comment.** @param o an observer to be added.* @throws NullPointerException if the parameter o is null.*/public synchronized void addObserver(Observer o) {if (o == null)throw new NullPointerException();if (!obs.contains(o)) {obs.addElement(o);}}/*** Deletes an observer from the set of observers of this object.* Passing <CODE>null</CODE> to this method will have no effect.* @param o the observer to be deleted.*/public synchronized void deleteObserver(Observer o) {obs.removeElement(o);}/*** If this object has changed, as indicated by the* <code>hasChanged</code> method, then notify all of its observers* and then call the <code>clearChanged</code> method to* indicate that this object has no longer changed.* <p>* Each observer has its <code>update</code> method called with two* arguments: this observable object and <code>null</code>. In other* words, this method is equivalent to:* <blockquote><tt>* notifyObservers(null)</tt></blockquote>** @see java.util.Observable#clearChanged()* @see java.util.Observable#hasChanged()* @see java.util.Observer#update(java.util.Observable, java.lang.Object)*/public void notifyObservers() {notifyObservers(null);}/*** If this object has changed, as indicated by the* <code>hasChanged</code> method, then notify all of its observers* and then call the <code>clearChanged</code> method to indicate* that this object has no longer changed.* <p>* Each observer has its <code>update</code> method called with two* arguments: this observable object and the <code>arg</code> argument.** @param arg any object.* @see java.util.Observable#clearChanged()* @see java.util.Observable#hasChanged()* @see java.util.Observer#update(java.util.Observable, java.lang.Object)*/public void notifyObservers(Object arg) {/** a temporary array buffer, used as a snapshot of the state of* current Observers.*/Object[] arrLocal;synchronized (this) {/* We don't want the Observer doing callbacks into* arbitrary code while holding its own Monitor.* The code where we extract each Observable from* the Vector and store the state of the Observer* needs synchronization, but notifying observers* does not (should not). The worst result of any* potential race-condition here is that:* 1) a newly-added Observer will miss a* notification in progress* 2) a recently unregistered Observer will be* wrongly notified when it doesn't care*/if (!changed)return;arrLocal = obs.toArray();clearChanged();}for (int i = arrLocal.length-1; i>=0; i--)((Observer)arrLocal[i]).update(this, arg);}/*** Clears the observer list so that this object no longer has any observers.*/public synchronized void deleteObservers() {obs.removeAllElements();}/*** Marks this <tt>Observable</tt> object as having been changed; the* <tt>hasChanged</tt> method will now return <tt>true</tt>.*/protected synchronized void setChanged() {changed = true;}/*** Indicates that this object has no longer changed, or that it has* already notified all of its observers of its most recent change,* so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.* This method is called automatically by the* <code>notifyObservers</code> methods.** @see java.util.Observable#notifyObservers()* @see java.util.Observable#notifyObservers(java.lang.Object)*/protected synchronized void clearChanged() {changed = false;}/*** Tests if this object has changed.** @return <code>true</code> if and only if the <code>setChanged</code>* method has been called more recently than the* <code>clearChanged</code> method on this object;* <code>false</code> otherwise.* @see java.util.Observable#clearChanged()* @see java.util.Observable#setChanged()*/public synchronized boolean hasChanged() {return changed;}/*** Returns the number of observers of this <tt>Observable</tt> object.** @return the number of observers of this object.*/public synchronized int countObservers() {return obs.size();} } public interface Observer {/*** This method is called whenever the observed object is changed. An* application calls an <tt>Observable</tt> object's* <code>notifyObservers</code> method to have all the object's* observers notified of the change.** @param o the observable object.* @param arg an argument passed to the <code>notifyObservers</code>* method.*/void update(Observable o, Object arg); }7.工廠模式
這里講一下比較繞的 抽象工廠模式。
使用工廠模式可以使我們客戶端調用的時候變得簡單,只需要修改一個工廠模式封裝好的產品就行。
例子:
3. 人是一個產品,魔法精靈也是產品要求如何更加簡潔的增加其他的產品
7.1代碼
Ak47
public class AK47 extends Weapon {public void shoot(){System.out.println("shoot----");} }Car
package com.monkey.factory.abstractfactory;import com.monkey.factory.Moveable;public class Car extends Vehicle {public void go(){System.out.println("car dididid........");} }Bread
package com.monkey.factory.abstractfactory;public class Bread extends Food {public void eat(){System.out.println("eatBread......");} }MagicStick
package com.monkey.factory.abstractfactory;public class MagicStick extends Weapon {public void shoot(){System.out.println("魔法棒----");} }MushRoom
package com.monkey.factory.abstractfactory;public class MushRoom extends Food {public void eat(){System.out.println("mushroom-----");} }Broom
package com.monkey.factory.abstractfactory;public class Broom extends Vehicle {public void go(){System.out.println("魔法世界的人開broom----");}}7.2抽象出來的三個抽象類
package com.monkey.factory.abstractfactory;public abstract class Food {abstract void eat(); } package com.monkey.factory.abstractfactory;public abstract class Vehicle {abstract void go(); } package com.monkey.factory.abstractfactory;public abstract class Weapon {abstract void shoot();}7.3 把三個抽象類放到一個抽象類中封裝
package com.monkey.factory.abstractfactory;public abstract class AbstractFactory {abstract Food createFood();abstract Vehicle createVehicle();abstract Weapon createWeapon(); }7.4 每個產品增加自己產品抽象類,繼承(extends)抽象父類
7.41現代世界的人
package com.monkey.factory.abstractfactory;public class ModernFactory extends AbstractFactory{@OverrideFood createFood() {return new Bread();}@OverrideVehicle createVehicle() {return new Car();}@OverrideWeapon createWeapon() {return new AK47();} }7.42魔法世界的人
package com.monkey.factory.abstractfactory;public class MagicStickFactory extends AbstractFactory {@OverrideFood createFood() {return new MushRoom();}@OverrideVehicle createVehicle() {return new Broom();}@OverrideWeapon createWeapon() {return new MagicStick();} }7.43客戶端進行調用,修改MagicStickFactory這個產品就可以進行不同的調用
package com.monkey.factory.abstractfactory;import com.monkey.factory.Moveable; import com.monkey.factory.Plane;public class Main {public static void main(String[] args) { // new Car().go(); // // new Plane().go();AbstractFactory a = new MagicStickFactory();Food food = a.createFood();food.eat();Weapon weapon = a.createWeapon();weapon.shoot();Vehicle vehicle = a.createVehicle();vehicle.go();} }總結
以上是生活随笔為你收集整理的java详细设计模式有代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GitHub 披露宕机原因;谷歌前 AI
- 下一篇: 数据结构试卷及答案(二)