源碼git地址 https://github.com/dlovetco/designMode
在項目中有可能我們會需要建立許許多多個類似的對象,這些對象之間的不同可能僅僅是參數不同。盲目地不斷new會不斷加重服務器負擔,此時我們可以考慮複用一些對象。
問題提出
小明做外包要建立許多個網站。有博客類的,購物類的等等。同類的網站結構幾乎差不多,不同的只是某些地方的數據,像一些賬戶信息,文字內容。用代碼實現這個場景。
享元模式
運用共享技術有效地支持大量細粒度的對象。
package flyweight;
import java.util.HashMap;
import java.util.Map;
public class FlyWeight {
public static void main(String[] args) {
User ming = new User();
ming.setUsername("小明");
User gang = new User();
gang.setUsername("小剛");
//建立兩個博客
Website blog1 = WebsiteFactory.getWebsite("博客");
blog1.show(ming);
Website blog2 = WebsiteFactory.getWebsite("博客");
blog2.show(gang);
//建立兩個購物網站
Website shopping1 = WebsiteFactory.getWebsite("購物網站");
shopping1.show(ming);
Website shopping2 = WebsiteFactory.getWebsite("購物網站");
shopping2.show(gang);
System.out.println(WebsiteFactory.getWebsizeNum());
}
}
class WebsiteFactory {
private static Map<String, Website> websiteMap = new HashMap<>();
//檢查有沒有已存在同一類型的對象
public static Website getWebsite(String type) {
Website website = websiteMap.get(type);
if (website == null) {
website = new ConcreteWebsite(type);
websiteMap.put(type, website);
}
return website;
}
public static int getWebsizeNum() {
return websiteMap.size();
}
}
/**
* 網站接口
*/
interface Website {
//User是外部參數
void show(User user);
}
class ConcreteWebsite implements Website {
public ConcreteWebsite(String websiteType) {
this.websiteType = websiteType;
}
//網站類型
private String websiteType;
@Override
public void show(User user) {
System.out.println("網站分類:" + websiteType + " 用戶名:" + user.getUsername());
}
}
class User {
public void setUsername(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
private String username;
}
享元模式的特點就是使用一個額外的類來保存已創建的對象。當客戶端試圖新建對象時都會先查看一遍有沒有已經建立好的相似的對象。每個對象不同地方就使用參數傳入,如上述例子中的user信息類。這些變化的信息稱之爲外部狀態,而每個對象中不會隨着環境改變而改變的信息稱之爲內部狀態。
應用場景:
一個應用程序中使用大量的對象,而大量的這些對象造成了很大的存儲開銷時就應該考慮使用;還有就是對象的大多數的狀態是外部狀態,如果刪除對象的外部狀態,那麼可以使用相對較少的共享對象取代很多組對象,此時可以考慮使用享元狀態。
plantuml
@startuml
class WebsiteFactory{
Map<String, Website> websiteMap
getWebsite(String type)
getWebsizeNum()
}
Website <..* WebsiteFactory
interface Website{
{abstract}show(User user)
}
Website <|.. ConcreteWebsite
class ConcreteWebsite{
show(User user)
}
User <.. Website
class User{
String name
}
@enduml