Java設(shè)計(jì)模式之享元模式
本文介紹了Java設(shè)計(jì)模式之享元模式,供大家參考,具體內(nèi)容如下
1、關(guān)于享元模式
享元模式有點(diǎn)類似于單例模式,都是只生成一個(gè)對(duì)象被共享使用。享元模式主要目的就是讓多個(gè)對(duì)象實(shí)現(xiàn)共享,減少不會(huì)要額內(nèi)存消耗,將多個(gè)對(duì)同一對(duì)象的訪問集中起來,不必為每個(gè)訪問者創(chuàng)建一個(gè)單獨(dú)的對(duì)象,以此來降低內(nèi)存的消耗。
2、享元模式結(jié)構(gòu)圖

因?yàn)橄碓J浇Y(jié)構(gòu)比較復(fù)雜,一般結(jié)合工廠模式一起使用,在它的結(jié)構(gòu)圖中包含了一個(gè)享元工廠類。
在享元模式結(jié)構(gòu)圖中包含如下幾個(gè)角色:
Flyweight(抽象享元類):通常是一個(gè)接口或抽象類,在抽象享元類中聲明了具體享元類公共的方法,這些方法可以向外界提供享元對(duì)象的內(nèi)部數(shù)據(jù)(內(nèi)部狀態(tài)),同時(shí)也可以通過這些方法來設(shè)置外部數(shù)據(jù)(外部狀態(tài))。
ConcreteFlyweight(具體享元類):它實(shí)現(xiàn)了抽象享元類,其實(shí)例稱為享元對(duì)象;在具體享元類中為內(nèi)部狀態(tài)提供了存儲(chǔ)空間。通常我們可以結(jié)合單例模式來設(shè)計(jì)具體享元類,為每一個(gè)具體享元類提供唯一的享元對(duì)象。
UnsharedConcreteFlyweight(非共享具體享元類):并不是所有的抽象享元類的子類都需要被共享,不能被共享的子類可設(shè)計(jì)為非共享具體享元類;當(dāng)需要一個(gè)非共享具體享元類的對(duì)象時(shí)可以直接通過實(shí)例化創(chuàng)建。
FlyweightFactory(享元工廠類):享元工廠類用于創(chuàng)建并管理享元對(duì)象,它針對(duì)抽象享元類編程,將各種類型的具體享元對(duì)象存儲(chǔ)在一個(gè)享元池中,享元池一般設(shè)計(jì)為一個(gè)存儲(chǔ)“鍵值對(duì)”的集合(也可以是其他類型的集合),可以結(jié)合工廠模式進(jìn)行設(shè)計(jì);當(dāng)用戶請(qǐng)求一個(gè)具體享元對(duì)象時(shí),享元工廠提供一個(gè)存儲(chǔ)在享元池中已創(chuàng)建的實(shí)例或者創(chuàng)建一個(gè)新的實(shí)例(如果不存在的話),返回新創(chuàng)建的實(shí)例并將其存儲(chǔ)在享元池中。
3、享元模式的實(shí)現(xiàn)
在享元模式中引入了享元工廠類,享元工廠類的作用在于提供一個(gè)用于存儲(chǔ)享元對(duì)象的享元池,當(dāng)用戶需要對(duì)象時(shí),首先從享元池中獲取,如果享元池中不存在,則創(chuàng)建一個(gè)新的享元對(duì)象返回給用戶,并在享元池中保存該新增對(duì)象。
接下來,實(shí)現(xiàn)一個(gè)登陸的享元模式。
1、用戶類
/**
* 用戶類
* @author 董秀才
*
*/
public class User {
private String username; // 用戶名
private String password; // 密碼
public User(String username,String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
2、抽象的登陸者(抽象享元類)
/**
* 登陸者--抽象享元類
* @author 董秀才
*
*/
public abstract class Loginer {
//登陸--享元類公共方法
public abstract void login(User user);
}
3、具體的登陸者(具體享元類)
/**
* 具體享元類
* @author 董秀才
*
*/
public class ConcreteLoginer extends Loginer{
// 登陸者憑證
private String loginerKey = "";
public ConcreteLoginer(String loginerKey) {
this.loginerKey = loginerKey;
}
@Override
public void login(User user) {
System.out.println("登陸者憑證:" + this.loginerKey+",用戶名:" + user.getUsername() + ",密碼:" + user.getPassword());
}
}
4、具體登陸者的工廠類(享元工廠類)
/**
* 享元工廠類
* @author 董秀才
*
*/
public class ConcreteLoginerFactory {
// map充當(dāng)對(duì)象享元池
private static Map<String,ConcreteLoginer> loginerMap = new HashMap<String, ConcreteLoginer>();
public static ConcreteLoginer getConcreteLoginer(String key) {
// 從享元池中拿 登陸者對(duì)象
ConcreteLoginer concreteLoginer = loginerMap.get(key);
// 如果享元池中沒有此對(duì)象
if(concreteLoginer == null) {
// 創(chuàng)建對(duì)象
concreteLoginer = new ConcreteLoginer(key);
// 存到享元池中
loginerMap.put(key, concreteLoginer);
}
// 返回對(duì)象
return concreteLoginer;
}
// 返回享元池對(duì)象數(shù)量
public static int getSize() {
return loginerMap.size();
}
}
5、測(cè)試類
/**
* 博客測(cè)試類
* @author 董秀才
*
*/
public class MainTest {
public static void main(String[] args) {
// 去工廠拿對(duì)象
ConcreteLoginer concreteLoginer_1 = ConcreteLoginerFactory.getConcreteLoginer("csdn");
concreteLoginer_1.login(new User("董秀才","123456"));
ConcreteLoginer concreteLoginer_2 = ConcreteLoginerFactory.getConcreteLoginer("csdn");
concreteLoginer_2.login(new User("董秀才","123456"));
ConcreteLoginer concreteLoginer_3 = ConcreteLoginerFactory.getConcreteLoginer("csdn");
concreteLoginer_3.login(new User("董秀才","123456"));
// 測(cè)試是否是同一個(gè)對(duì)象
System.out.println("是否是同一個(gè)對(duì)象:" + ((concreteLoginer_1==concreteLoginer_2)&&(concreteLoginer_2 == concreteLoginer_3)));
// 第二登陸者
ConcreteLoginer concreteLoginer_4 = ConcreteLoginerFactory.getConcreteLoginer("博客園");
concreteLoginer_4.login(new User("董才才","654321"));
ConcreteLoginer concreteLoginer_5 = ConcreteLoginerFactory.getConcreteLoginer("博客園");
concreteLoginer_5.login(new User("董才才","654321"));
ConcreteLoginer concreteLoginer_6 = ConcreteLoginerFactory.getConcreteLoginer("博客園");
concreteLoginer_6.login(new User("董才才","654321"));
System.out.println("是否是同一個(gè)對(duì)象:" + ((concreteLoginer_4==concreteLoginer_5)&&(concreteLoginer_5 == concreteLoginer_6)));
// 工廠類中享元池中對(duì)象數(shù)量
System.out.println("享元池size:" + ConcreteLoginerFactory.getSize());
}
}
6、運(yùn)行結(jié)果

4、總結(jié)
從上面代碼和運(yùn)行結(jié)果這可以看到,同一個(gè)登陸者登陸時(shí)是 "享" 用同一個(gè)登陸者對(duì)象。在享元對(duì)象池中只有兩個(gè)對(duì)象。
享元模式優(yōu)點(diǎn)
享元模式的外部狀態(tài)相對(duì)獨(dú)立,使得對(duì)象可以在不同的環(huán)境中被復(fù)用(共享對(duì)象可以適應(yīng)不同的外部環(huán)境)
享元模式可共享相同或相似的細(xì)粒度對(duì)象,從而減少了內(nèi)存消耗,同時(shí)降低了對(duì)象創(chuàng)建與垃圾回收的開銷
享元模式缺點(diǎn)
外部狀態(tài)由客戶端保存,共享對(duì)象讀取外部狀態(tài)的開銷可能比較大
享元模式要求將內(nèi)部狀態(tài)與外部狀態(tài)分離,這使得程序的邏輯復(fù)雜化,同時(shí)也增加了狀態(tài)維護(hù)成本
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
關(guān)于Spring Boot和Kotlin的聯(lián)合開發(fā)
這篇文章主要介紹了關(guān)于Spring Boot和Kotlin的聯(lián)合開發(fā),需要的朋友可以參考下2017-06-06
Java進(jìn)階學(xué)習(xí):jar打包詳解
Java進(jìn)階學(xué)習(xí):jar打包詳解...2006-12-12
SpringBoot多級(jí)緩存實(shí)現(xiàn)方案總結(jié)
所謂多級(jí)緩存,是指在整個(gè)系統(tǒng)架構(gòu)的不同系統(tǒng)層面進(jìn)行數(shù)據(jù)緩存,以提升訪問速度,多級(jí)緩存就是為了解決項(xiàng)目服務(wù)中單一緩存使用不足的缺點(diǎn),本文我們將給大家總結(jié)了SpringBoot多級(jí)緩存實(shí)現(xiàn)方案,需要的朋友可以參考下2023-08-08
java+jdbc+mysql+socket搭建局域網(wǎng)聊天室
這篇文章主要為大家詳細(xì)介紹了java+jdbc+mysql+socket搭建局域網(wǎng)聊天室,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
深入剖析Java中的synchronized關(guān)鍵字
在 Java 程序中,我們可以利用 synchronized 關(guān)鍵字來對(duì)程序進(jìn)行加鎖,它既可以用來聲明一個(gè) synchronized 代碼塊,也可以直接標(biāo)記靜態(tài)方法或者實(shí)例方法,本文就帶大家深入了解Java中的synchronized關(guān)鍵字,感興趣的同學(xué)可以參考閱讀2023-06-06
SpringCloud Nacos配置中心管理超詳細(xì)講解
這篇文章主要介紹了Springcloud中的Nacos服務(wù)配置,本文以用戶微服務(wù)為例,進(jìn)行統(tǒng)一的配置,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11
Java OpenCV實(shí)現(xiàn)人臉識(shí)別過程詳解
這篇文章主要介紹了Java OpenCV實(shí)現(xiàn)人臉識(shí)別過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08

