Java RMI的工厂模式应用 - 高飞网
637 人阅读

Java RMI的工厂模式应用

2017-07-28 02:09:46

    什么是工厂,为什么用?这里所谓的工厂,是指实现了工厂模式的程序片段。通常当你需要一个对象去控制其他对象的创建和访问时,工厂模式是非常有用的。通过在RMI中应用工厂模式,你可以大大的减少需要注册到RMI注册器中的对象。

现实世界中的工厂

银行

    当你去银行向你的账户存钱时,你肯定不会走到仓库,拉开写着你名字的抽屉,把钱放进去,把抽屉合上,离开。想一下你最初建立或开启账户时的情景。你可能是到银行,与账户经理交谈一番,填一个表格,之后,他们给你一些做些检查,一个存折,或者银行卡,你就可以在之后访问你的账户了。

    这里的账户经理就是一个工厂的例子。这个人或自动提款机(Automated Taller Machine,ATM)做为一个管理者的角色,控制着每个账户的创建或访问。

图书馆

    让我们想一下我们是如何从图书馆借书、光盘或录像带到家里的。在你查询任何资料之后,你必须先从图书管管理员那里,申请到一个借书证。在这种情况下,图书馆管理员可以看作是一个工厂,因为他控制着新借书证的发放。

    一旦你拥有了借书证,你就可以不再需要任何麻烦进入图书馆,直接拿走你要的资料了吗?当然不是。在你拿走你的资料之前,你还要检查你的书、CD或录象带,并出示你的借书证,你猜想,管理员用你的借书证,去图书馆数据库中查看你有没有滞纳金,并把这些资料记录你借走了。在这种情况下,图书馆管理员可以被看成是一个图书的工厂,他控制着你获取这些图书。

在RMI中,工厂是如何工作的?

    就像其他Java RM程序一样,有几个基本的角色,服务端生产一个或多个远程对象,他们都实现了远程接口;客户端,访问名字服务去获取远程对象的引用;rmiregistry,促使客户端连接到服务端。

    看下面的图片和步骤,你可能会有下面的疑问

  1. 客户端要理解两个远程接口,Facotry和Product
  2. FacotryImpl实现了Factory接口,ProductImpl实现了Product接口

Illustrates the 6 actions listed below.

  1. FactoryImpl用rmiregistry注册
  2. 客户端获取Factory的引用
  3. rmiregistry返回远程对象FactoryImpl的引用
  4. 客户端调用在FactoryImpl对象上的远程方法,包含了到ProductImpl的引用
  5. FactoryImpl返回了一个已存在或基于每次客户端请求生产的ProductImpl对象的远程引用
  6. 客户端调用ProductImpl的远程方法。

用Java RMI实现银行和图书馆访问接口

银行接口

    在代码层面,AccountManager将实现远程接口,并声明一至多个远程方法。这些方法将返回一些实现了Account接口的对象。类似地,Account接口将实现所有的可以在账户上的操作行为,如存款,取现,获取余额、查询账单等。

    用Java RMI,只有AccountManager的实现被注册到RMI 注册器中,而AccountManager以工厂模式实现,返回一系列的Account的远程对象的引用。

IAccountManager.java

package rmi.factory.ro;

import java.rmi.Remote;
import java.rmi.RemoteException;

import rmi.factory.service.impl.IAccount;

public interface IAccountManager extends Remote{
	public IAccount getAccount()throws RemoteException;
}

AccountManagerImpl.java

package rmi.factory.ro;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import rmi.factory.service.impl.AccountImpl;
import rmi.factory.service.impl.IAccount;

public class AccountManagerImpl implements IAccountManager {
	private Map<String,IAccount> remoteInterfaces = new ConcurrentHashMap<>();
	@Override
	public IAccount getAccount() throws RemoteException {
		if (remoteInterfaces.get("account") == null) {
			IAccount account = new AccountImpl();
			IAccount stub = (IAccount) UnicastRemoteObject.exportObject(account,0);
			remoteInterfaces.put("account", stub);
		}
		return remoteInterfaces.get("account");
	}

}

IAccount.java

package rmi.factory.service.impl;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;

public interface IAccount extends Remote {
	/**
	 * 账号存钱
	 * 
	 * @param id
	 * @param money
	 * @return
	 */
	boolean depositing(int id, float money) throws RemoteException;

	/**
	 * 取钱
	 * 
	 * @param id
	 * @param money
	 * @return
	 */
	boolean withdrawing(int id, float money) throws RemoteException;

	/**
	 * 帐户余额
	 * 
	 * @param id
	 * @return
	 */
	float getAccountBalance(int id) throws RemoteException;

	/**
	 * 交易记录
	 * @param id
	 * @return
	 * @throws RemoteException
	 */
	List<String> listRecentTrans(int id) throws RemoteException;
}


AccountImpl.java

package rmi.factory.service.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class AccountImpl implements IAccount, Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 197313594447130292L;
	private Map<Integer, Float> accounts = new ConcurrentHashMap<>();
	private Map<Integer, List<String>> recentTrans = new ConcurrentHashMap<>();

	public AccountImpl() {
		accounts.put(1, 0.0f);
		recentTrans.put(1, new ArrayList<String>());
	}

	@Override
	public boolean depositing(int id, float money) {
		System.out.println("depositing...");
		Float cur = accounts.get(1);
		accounts.put(id, cur + money);
		recentTrans.get(id).add(String.format("id:%d depositing money:%f", id, money));
		return false;
	}

	@Override
	public boolean withdrawing(int id, float money) {
		System.out.println("withdrawing...");
		Float cur = accounts.get(1);
		accounts.put(1, cur - money);
		recentTrans.get(id).add(String.format("id:%d withdrawing money:%f", id, money));
		return false;
	}

	@Override
	public float getAccountBalance(int id) {
		System.out.println("getAccountBalance...");
		Float cur = accounts.get(1);
		recentTrans.get(id).add(String.format("id:%d getAccountBalance ", id));
		return cur;
	}

	@Override
	public List<String> listRecentTrans(int id) {
		return recentTrans.get(id);
	}

}


Server.java

package rmi.factory;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import rmi.factory.ro.AccountManagerImpl;
import rmi.factory.ro.IAccountManager;

public class Server {
	public static void main(String[] args) {
		try {
			AccountManagerImpl am = new AccountManagerImpl();
			IAccountManager amStub = (IAccountManager) UnicastRemoteObject.exportObject(am, 0);

			Registry registry = LocateRegistry.getRegistry();
			registry.rebind("accountManager", amStub);
			//
			System.out.println("account server start");
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}
}


Client.java

package rmi.factory;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.List;

import rmi.factory.ro.IAccountManager;
import rmi.factory.service.impl.IAccount;

public class Client {
	public static void main(String[] args) {
	    try {
	        Registry registry = LocateRegistry.getRegistry();
	        IAccountManager accountManager = (IAccountManager) registry.lookup("accountManager");
	        
	        IAccount account = accountManager.getAccount();
	        System.out.println(account);
	        account.depositing(1, 11.5f);
	        account.withdrawing(1, 0.5f);
	        System.out.println("balance:"+account.getAccountBalance(1));
	        List<String> list = account.listRecentTrans(1);
	        for(String s:list){
	        	System.out.println(s);
	        }
	        System.out.println();
        } catch (RemoteException | NotBoundException e) {
	        e.printStackTrace();
        }
    }
}


输出:

Proxy[IAccount,RemoteObjectInvocationHandler[UnicastRef [liveRef: [endpoint:[10.10.89.64:61414](remote),objID:[-67c2cd4a:15b3c385f65:-7ffc, -3025624048436407128]]]]]
balance:44.0
id:1 depositing money:11.500000
id:1 withdrawing money:0.500000
id:1 getAccountBalance 
id:1 depositing money:11.500000
id:1 withdrawing money:0.500000
id:1 getAccountBalance 
id:1 depositing money:11.500000
id:1 withdrawing money:0.500000
id:1 getAccountBalance 
id:1 depositing money:11.500000
id:1 withdrawing money:0.500000
id:1 getAccountBalance 


图书馆接口

    Librarian是一个远程接口,包含了一到多个方法返回实现了LibraryCard接口的对象,另外Librarian接口提供了方法,让你访问图书,CD,录像带,实现了Loanable接口。

    用Java RMI,只有Librarian注册到RMI的registry中,Librarian是一个工厂模式的实现,返回了实现接口LibraryCard和Loanable 接口的远程对象的引用。




还没有评论!