設計模式12—設計模式之代理模式(Proxy)(結構型)

來源:互聯網
上載者:User
1.情境類比

考慮這樣一個實際應用:
HR提出,當選擇一個部門或者是分公司的時候,要把所有的分公司下的員工顯示出來,而且不要翻頁,方便進行業務處理,只需要顯示姓名即可,但是點擊姓名會出現這位員工的詳細資料。
2.不用模式解決

資料庫代碼就不寫了,總的來說就是使用者表和部門表
直接上java代碼
2.1.描述使用者資料的對象

package demo10.proxy.example1;/** * 描述使用者資料的對象 */public class UserModel {/** * 使用者編號 */private String userId;/** * 使用者姓名 */private String name;/** * 部門編號 */private String depId;/** * 性別 */private String sex;public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDepId() {return depId;}public void setDepId(String depId) {this.depId = depId;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}@Overridepublic String toString(){return "userId="+userId+",name="+name+",depId="+depId+",sex="+sex+"\n";}}
2.2.實現樣本要求的功能
package demo10.proxy.example1;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.Collection;/** * 實現樣本要求的功能 */public class UserManager {/** * 根據部門編號來擷取該部門下的所有人員 *  * @param depId *        部門編號 * @return 該部門下的所有人員 */public Collection<UserModel> getUserByDepId(String depId) throws Exception {Collection<UserModel> col = new ArrayList<UserModel>();Connection conn = null;try {conn = this.getConnection();String sql = "select * from tbl_user u,tbl_dep d " + "where u.depId=d.depId and d.depId like ?";PreparedStatement pstmt = conn.prepareStatement(sql);pstmt.setString(1, depId + "%");ResultSet rs = pstmt.executeQuery();while (rs.next()) {UserModel um = new UserModel();um.setUserId(rs.getString("userId"));um.setName(rs.getString("name"));um.setDepId(rs.getString("depId"));um.setSex(rs.getString("sex"));col.add(um);}rs.close();pstmt.close();} finally {conn.close();}return col;}/** * 擷取與資料庫的串連 *  * @return 資料庫連接 */private Connection getConnection() throws Exception {Class.forName("oracle.jdbc.driver.OracleDriver");return DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "test", "test");}}
2.3.用戶端
package demo10.proxy.example1;import java.util.*;public class Client {public static void main(String[] args) throws Exception{UserManager userManager = new UserManager();Collection<UserModel> col = userManager.getUserByDepId("0101");System.out.println(col);}}
3.問題所在

當一次性訪問的資料條數過多,並且每條資料的資料量又很大的情況下,就會消耗較多的記憶體。那麼如何解決這個問題呢?
4.使用代理模式解決4.1問題思考

其實很簡單,我們開始時候只要進行名字的顯示,點擊名字以後才會進入詳細資料,所以,我們可以在之間加一個代理,專門負責控制對某條資料的訪問,當點擊名字以後,再重新查詢一下資料庫即可,實際上就是以時間換空間的策略。
4.2代理模式的結構和說明

4.3代理模式範例程式碼
package demo10.proxy.example2;/** * 抽象的目標介面,定義具體的目標對象和代理公用的介面 */public interface Subject {/** * 示意方法:一個抽象的要求方法 */public void request();}package demo10.proxy.example2;/** * 具體的目標對象,是真正被代理的對象 */public class RealSubject implements Subject{public void request() {//執行具體的功能處理}}package demo10.proxy.example2;/** * 代理對象 */public class Proxy implements Subject{/** * 持有被代理的具體的目標對象 */private RealSubject realSubject=null;/** * 構造方法,傳入被代理的具體的目標對象 * @param realSubject 被代理的具體的目標對象 */public Proxy(RealSubject realSubject){this.realSubject = realSubject;}public void request() {//在轉調具體的目標對象前,可以執行一些功能處理//轉調具體的目標對象的方法realSubject.request();//在轉調具體的目標對象後,可以執行一些功能處理}}
5.使用代理模式重寫樣本5.1定義使用者資料對象的介面
package demo10.proxy.example3;/** * 定義使用者資料對象的介面 */public interface UserModelApi {public String getUserId();public void setUserId(String userId);public String getName();public void setName(String name);public String getDepId();public void setDepId(String depId);public String getSex();public void setSex(String sex);}
5.2描述使用者資料的對象,沒有什麼變化
package demo10.proxy.example3;/** * 描述使用者資料的對象 */public class UserModel implements UserModelApi{/** * 使用者編號 */private String userId;/** * 使用者姓名 */private String name;/** * 部門編號 */private String depId;/** * 性別 */private String sex;public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDepId() {return depId;}public void setDepId(String depId) {this.depId = depId;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}@Overridepublic String toString(){return "userId="+userId+",name="+name+",depId="+depId+",sex="+sex+"\n";}}
5.3代理對象,代理使用者資料對象
package demo10.proxy.example3;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;/** * 代理對象,代理使用者資料對象 */public class Proxy implements UserModelApi {/** * 持有被代理的具體的目標對象 */private UserModel realSubject = null;/** * 構造方法,傳入被代理的具體的目標對象 *  * @param realSubject *        被代理的具體的目標對象 */public Proxy(UserModel realSubject) {this.realSubject = realSubject;}/** * 標示是否已經重新裝載過資料了 */private boolean loaded = false;public String getUserId() {return realSubject.getUserId();}public void setUserId(String userId) {realSubject.setUserId(userId);}public String getName() {return realSubject.getName();}public void setName(String name) {realSubject.setName(name);}public void setDepId(String depId) {realSubject.setDepId(depId);}public void setSex(String sex) {realSubject.setSex(sex);}public String getDepId() {// 需要判斷是否已經裝載過了if (!this.loaded) {// 從資料庫中重新裝載reload();// 設定重新裝載的標誌為truethis.loaded = true;}return realSubject.getDepId();}public String getSex() {if (!this.loaded) {reload();this.loaded = true;}return realSubject.getSex();}/** * 重新查詢資料庫以擷取完整的使用者資料 */private void reload() {System.out.println("重新查詢資料庫擷取完整的使用者資料,userId==" + realSubject.getUserId());Connection conn = null;try {conn = this.getConnection();String sql = "select * from tbl_user where userId=? ";PreparedStatement pstmt = conn.prepareStatement(sql);pstmt.setString(1, realSubject.getUserId());ResultSet rs = pstmt.executeQuery();if (rs.next()) {// 只需要重新擷取除了userId和name外的資料realSubject.setDepId(rs.getString("depId"));realSubject.setSex(rs.getString("sex"));}rs.close();pstmt.close();} catch (Exception err) {err.printStackTrace();} finally {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}public String toString() {return "userId=" + getUserId() + ",name=" + getName() + ",depId=" + getDepId() + ",sex=" + getSex() + "\n";}private Connection getConnection() throws Exception {Class.forName("oracle.jdbc.driver.OracleDriver");return DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "test", "test");}}
5.4實現樣本要求的功能
package demo10.proxy.example3;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.Collection;/** * 實現樣本要求的功能 */public class UserManager {/** * 根據部門編號來擷取該部門下的所有人員 *  * @param depId *        部門編號 * @return 該部門下的所有人員 */public Collection<UserModelApi> getUserByDepId(String depId) throws Exception {Collection<UserModelApi> col = new ArrayList<UserModelApi>();Connection conn = null;try {conn = this.getConnection();// 只需要查詢userId和name兩個值就可以了String sql = "select u.userId,u.name " + "from tbl_user u,tbl_dep d " + "where u.depId=d.depId and d.depId like ?";PreparedStatement pstmt = conn.prepareStatement(sql);pstmt.setString(1, depId + "%");ResultSet rs = pstmt.executeQuery();while (rs.next()) {// 這裡是建立的代理對象,而不是直接建立UserModel的對象Proxy proxy = new Proxy(new UserModel());// 只是設定userId和name兩個值就可以了proxy.setUserId(rs.getString("userId"));proxy.setName(rs.getString("name"));col.add(proxy);}rs.close();pstmt.close();} finally {conn.close();}return col;}/** * 擷取與資料庫的串連 *  * @return 資料庫連接 */private Connection getConnection() throws Exception {Class.forName("oracle.jdbc.driver.OracleDriver");return DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "test", "test");}}
5.5用戶端測試
package demo10.proxy.example3;import java.util.*;public class Client {public static void main(String[] args) throws Exception{UserManager userManager = new UserManager();Collection<UserModelApi> col = userManager.getUserByDepId("0101");//如果只是顯示使用者名稱稱,那麼不需要重新查詢資料庫for(UserModelApi umApi : col){System.out.println("使用者編號:="+umApi.getUserId()+",使用者姓名:="+umApi.getName());}//如果訪問非使用者編號和使用者姓名外的屬性,那就會重新查詢資料庫for(UserModelApi umApi : col){System.out.println("使用者編號:="+umApi.getUserId()+",使用者姓名:="+umApi.getName()+",所屬部門:="+umApi.getDepId());}}}
6.模式講解6.1認識代理模式

代理模式是通過建立一個代理對象,用這個代理去代表真實的對象,用戶端得到這個對象以後,對用戶端沒有什麼影響,就跟得到了真實的對象一樣。當用戶端操作這個代理對象時候,實際上功能還是由真實的對象來完成,只不過是通過代理來操作的,也就是用戶端操作代理,代理操作真正的對象。
6.2代理模式調用

 
6.3思考代理模式

代理模式的本質是:控制對象訪問
代理模式通過代理目標對象,把代理對象和插入到用戶端和目標對象之間,從而為用戶端和目標對象之間引入一定的間接性。這種模式適用於查詢某個對象次數較少的情況下,否則會查詢多至N+1次

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.