Java單例模式詳解
一、引言
單例模式是設(shè)計模式中的一種,屬于創(chuàng)建型模式。在軟件工程中,單例模式確保一個類只有一個實例,并提供一個全局訪問點。這種模式常用于那些需要頻繁實例化然后引用,且創(chuàng)建新實例的開銷較大的類,例如數(shù)據(jù)庫連接池、緩存管理等。
二、單例模式定義
意圖:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。
主要解決:一個全局使用的類頻繁地創(chuàng)建與銷毀所造成的資源浪費問題。
何時使用:當(dāng)您想控制實例數(shù)目,節(jié)省系統(tǒng)資源的時候。
如何解決:判斷系統(tǒng)是否已經(jīng)有這個單例,如果有則返回,如果沒有則創(chuàng)建。
關(guān)鍵代碼:構(gòu)造函數(shù)是私有的。
三、Java實現(xiàn)單例模式的幾種方式
- 懶漢式(線程不安全)
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
這種方式在多線程環(huán)境下不能保證單例,因為多個線程可能同時進(jìn)入if條件判斷內(nèi)部,導(dǎo)致創(chuàng)建多個實例。
- 懶漢式(線程安全,同步方法)
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
通過在getInstance方法上加synchronized關(guān)鍵字使其變?yōu)橥椒椒?,解決了多線程環(huán)境下的安全性問題,但每次獲取實例都要進(jìn)行同步,性能損耗較大。
- 懶漢式(線程安全,雙重檢查鎖定 - DCL,推薦使用)
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
雙重檢查鎖定機制,首先判斷實例是否存在,若不存在才進(jìn)行同步處理,這樣既保證了線程安全,又避免了每次都進(jìn)行同步帶來的性能損耗。
- 餓漢式(靜態(tài)內(nèi)部類)
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
靜態(tài)內(nèi)部類的方式在類加載時就完成了初始化,既保證了線程安全,也避免了同步帶來的性能影響,同時也能保證單例對象的唯一性。
- 枚舉式(最安全,推薦使用)
public enum Singleton {
INSTANCE;
public void whateverMethod() {
// ...
}
}
枚舉類型的單例模式不僅能防止反射和反序列化的攻擊,而且寫法簡單,易于理解,是實現(xiàn)單例的最佳選擇。
四、注意事項
- 單例模式雖然能節(jié)約系統(tǒng)資源,但也可能造成全局狀態(tài)過多,增加系統(tǒng)的復(fù)雜度。
- 對于可序列化類的單例模式,需要重寫readResolve方法以防止反序列化時生成新的對象。
以上就是Java單例模式的詳細(xì)解讀,實際開發(fā)過程中應(yīng)根據(jù)具體場景選擇合適的實現(xiàn)方式。
Java工廠設(shè)計模式詳解
一、引言
工廠模式是面向?qū)ο笤O(shè)計模式中的一種,主要用來解決對象創(chuàng)建的問題,封裝了對象的創(chuàng)建過程,使客戶端不需要知道具體的實現(xiàn)類就能創(chuàng)建所需的對象。根據(jù)抽象程度的不同,工廠模式分為簡單工廠模式、工廠方法模式和抽象工廠模式。
二、工廠模式分類與定義
- 簡單工廠模式(Simple Factory Pattern)
意圖:提供一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類。
結(jié)構(gòu):由一個工廠類負(fù)責(zé)創(chuàng)建不同類的產(chǎn)品對象。
// 簡單工廠角色
public class ShapeFactory {
public Shape getShape(String type) {
if ("CIRCLE".equals(type)) {
return new Circle();
} else if ("RECTANGLE".equals(type)) {
return new Rectangle();
} else if ("SQUARE".equals(type)) {
return new Square();
} else {
throw new IllegalArgumentException("Invalid shape type");
}
}
}
// 抽象產(chǎn)品角色
abstract class Shape {
abstract void draw();
}
// 具體產(chǎn)品角色
class Circle extends Shape {
@Override
void draw() {
System.out.println("Drawing a circle...");
}
}
// 其他具體產(chǎn)品類...
- 工廠方法模式(Factory Method Pattern)
意圖:定義一個用于創(chuàng)建對象的接口,但讓子類決定實例化哪個類。工廠方法使一個類的實例化延遲到其子類。
結(jié)構(gòu):定義一個創(chuàng)建產(chǎn)品對象的接口,讓子類決定生產(chǎn)什么產(chǎn)品。
// 抽象工廠角色
interface ShapeFactory {
Shape createShape();
}
// 具體工廠角色
class CircleFactory implements ShapeFactory {
@Override
Shape createShape() {
return new Circle();
}
}
// 其他具體工廠類...
// 抽象產(chǎn)品角色
abstract class Shape {
abstract void draw();
}
// 具體產(chǎn)品角色
class Circle extends Shape {
@Override
void draw() {
System.out.println("Drawing a circle...");
}
}
// 其他具體產(chǎn)品類...
- 抽象工廠模式(Abstract Factory Pattern)
意圖:提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們的具體類。
結(jié)構(gòu):提供一個接口,用于創(chuàng)建相關(guān)或相互依賴對象家族的一系列對象,而無需指定具體類。
// 抽象工廠角色
interface ColorFactory {
Color getColor();
}
interface ShapeFactory {
Shape getShape();
}
// 具體工廠角色
class RedColorFactory implements ColorFactory {
@Override
Color getColor() {
return new RedColor();
}
}
class CircleShapeFactory implements ShapeFactory {
@Override
Shape getShape() {
return new Circle();
}
}
// 抽象產(chǎn)品角色
interface Color {
void fill();
}
interface Shape {
void draw();
}
// 具體產(chǎn)品角色
class RedColor implements Color {
@Override
void fill() {
System.out.println("Filling with red color...");
}
}
class Circle implements Shape {
@Override
void draw() {
System.out.println("Drawing a circle...");
}
}
// 其他具體產(chǎn)品類...
三、工廠模式優(yōu)缺點
-
優(yōu)點
- 將對象的創(chuàng)建和使用分離,使得系統(tǒng)耦合度降低。
- 提高代碼的可擴(kuò)展性,增加新的產(chǎn)品類型時只需要添加新的工廠或產(chǎn)品類,不影響已有的代碼。
-
缺點
- 當(dāng)產(chǎn)品種類較多時,會導(dǎo)致類爆炸,因為每新增一種產(chǎn)品就需要新增對應(yīng)的工廠類。
- 違反開閉原則,如果需要新增一個產(chǎn)品,除了新增產(chǎn)品類外,可能還需要修改工廠類或抽象工廠類。
四、適用場景
- 當(dāng)一個類不知道它所必須創(chuàng)建的對象的確切類時。
- 當(dāng)一個類希望它的使用者指定它所創(chuàng)建的對象類型時。
- 當(dāng)類將職責(zé)委托給多個幫助子類中的某一個,并且用戶希望可以動態(tài)地決定這個職責(zé)委托給哪個子類時。
通過上述介紹,您應(yīng)該對Java中的工廠設(shè)計模式有了較為深入的理解。在實際開發(fā)中,可以根據(jù)需求選擇合適的工廠模式來組織代碼,提高程序的靈活性和可維護(hù)性。
Java代理設(shè)計模式詳解
一、引言
代理設(shè)計模式(Proxy Design Pattern)是軟件設(shè)計中常用的行為型設(shè)計模式之一,它為其他對象提供一個代理以控制對這個對象的訪問。在Java編程中,代理模式的主要目的是為了在不改變原始目標(biāo)類代碼的基礎(chǔ)上,通過引入一個額外的代理類來擴(kuò)展或增強原有對象的功能。
1.1 定義
代理模式定義如下:
代理模式:給某個對象提供一個代理,并由代理對象控制對原對象的引用。代理模式能夠在客戶端與目標(biāo)對象之間增加一層間接層,從而實現(xiàn)對目標(biāo)對象功能的增強、控制或者過濾。
1.2 模式結(jié)構(gòu)
- Subject(抽象主題): 定義了真實主題和代理主題的公共接口,這樣代理可以作為真實主題的替代品。
- RealSubject(真實主題): 實際完成工作的類,也是代理所代表的真實對象。
- Proxy(代理): 保存一個對真實主題的引用,并且提供一個與真實主題相同的接口以便于在任何時候都可以將請求轉(zhuǎn)發(fā)給真實主題處理;同時,在轉(zhuǎn)發(fā)請求前或后執(zhí)行附加操作。
1.3 應(yīng)用場景
- 訪問控制:如權(quán)限驗證,只有經(jīng)過代理對象確認(rèn)之后才能訪問真實對象的方法。
- 功能增強:例如在方法調(diào)用前后添加日志記錄、事務(wù)管理等。
- 虛擬代理:延遲加載,如圖片預(yù)加載、數(shù)據(jù)庫連接池中的連接對象創(chuàng)建等。
- 遠(yuǎn)程代理:用于分布式系統(tǒng)中,代理對象負(fù)責(zé)與遠(yuǎn)程對象通信。
- 緩存代理:緩存結(jié)果以提高性能,當(dāng)請求數(shù)據(jù)時先檢查代理是否有緩存的結(jié)果。
- AOP(面向切面編程):Spring框架AOP模塊底層就使用了動態(tài)代理技術(shù)。
二、Java中的代理實現(xiàn)方式
在Java中,代理主要分為兩種類型:
2.1 靜態(tài)代理
靜態(tài)代理是在編譯期間就已經(jīng)確定代理類,代理類和被代理類的關(guān)系在代碼中硬編碼。
public interface Subject {
void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
// 真實對象的實際業(yè)務(wù)邏輯
}
}
public class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
beforeRequest(); // 在調(diào)用實際方法前的操作
realSubject.request();
afterRequest(); // 在調(diào)用實際方法后的操作
}
private void beforeRequest() {
// 添加前置邏輯,比如權(quán)限校驗
}
private void afterRequest() {
// 添加后置邏輯,比如日志記錄
}
}
2.2 動態(tài)代理
Java提供了動態(tài)生成代理類的技術(shù),主要有兩種實現(xiàn)機制:
2.2.1 JDK動態(tài)代理
JDK動態(tài)代理基于接口實現(xiàn),通過java.lang.reflect.Proxy
類和InvocationHandler
接口。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler {
private Object target;
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeInvoke(method);
Object result = method.invoke(target, args);
afterInvoke(method);
return result;
}
private void beforeInvoke(Method method) {
// 前置處理
}
private void afterInvoke(Method method) {
// 后置處理
}
}
// 使用示例
RealSubject realSubject = new RealSubject();
Subject proxy = (Subject) new JdkProxy().bind(realSubject);
proxy.request();
2.2.2 CGLIB代理
CGLIB庫是一個強大的高性能代碼生成庫,可以在運行期擴(kuò)展Java類與實現(xiàn)Java接口。它可以創(chuàng)建出一個被代理類的子類,因此不需要接口也能進(jìn)行代理。CGLIB常用于Spring AOP框架中,對于沒有實現(xiàn)接口的目標(biāo)類也能提供代理支持。文章來源:http://www.zghlxwxcb.cn/news/detail-820852.html
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
beforeInvoke(method);
Object result = proxy.invokeSuper(obj, args);
afterInvoke(method);
return result;
}
private void beforeInvoke(Method method) {
// 前置處理
}
private void afterInvoke(Method method) {
// 后置處理
}
public Object createProxy(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
// 使用示例
RealSubject realSubject = (RealSubject) new CglibProxy().createProxy(RealSubject.class);
((Subject) realSubject).request();
}
// 注意:這里假設(shè)RealSubject并未實現(xiàn)任何接口
三、總結(jié)
Java代理設(shè)計模式是一種重要的設(shè)計思想,它幫助開發(fā)者在不影響原始類的情況下,對類的行為進(jìn)行擴(kuò)展和控制。在實際開發(fā)中,無論是通過靜態(tài)代理還是動態(tài)代理,都能在很多場合發(fā)揮重要作用,尤其是在框架設(shè)計、服務(wù)治理、性能優(yōu)化以及AOP等領(lǐng)域得到廣泛應(yīng)用。學(xué)習(xí)并掌握代理模式有助于提升代碼的靈活性和可維護(hù)性。文章來源地址http://www.zghlxwxcb.cn/news/detail-820852.html
到了這里,關(guān)于Java設(shè)計模式---單例 工廠 代理模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!