一、单例模式(Singleton)
1、单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处:
1>某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销.
2>省去了new操作符,降低了系统内存的使用频率,减轻GC压力.
3>有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了.(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程.
2、单例三步骤: 1.构造函数私有化2.类中创建一个本类对象3.提供一个方法可以获取该对象.
3、对于该类的事物该怎么描述还是怎么描述,当需要内存中该类对象唯一时就加上面三步.
4、懒汉式和饿汉式,延迟加载,实际中使用饿汉式,懒汉式有线程问题 (在判断是否为空时cpu切换,可以加sync..锁定,但是效率低).
//饿汉式
class Single{
private static final Single s = new Single();
private Single(){}
public static Single getInstance(){
return s;
}
}
//懒汉式
class Ehanshi(){
private ehanshi(){} Ehanshi e = null;
public static Ehanshi getInstance(){
if(e==null){
--》此处切换cpu,会有线程问题
e = new Ehanshi();
}
}
}
//解决方式一(效率低,每次需要判断是否锁定)
class Ehanshi(){
private ehanshi(){} Ehanshi e = null;
public static Ehanshi synchronized getInstance(){
if(e==null){ e = new Ehanshi();}
}
}
//解决方式二 ,效率高 (但是还是建议使用饿汉式简单)
class Ehanshi(){
private ehanshi(){} Ehanshi e = null;
public static Ehanshi getInstance(){
if(e==null){
synchronized(Ehanshi.class){
if(e==null){
e = new Ehanshi();
}
}
}
}
}
5、使用案例:
例1:链接池可以使用单例模式,初始化的时候创建譬如100个connection对象,然后再需要的时候提供一个,用过之后返回到pool中,单例模式保证连接池有且只有一个.
例2:Spring 的 IoC 容器在默认情况下对所有托管对象都是进行了单例化处理的,scope可以配置单例还是多例.
例3:我们有时候项目简单的时候不想用spring,可以自己写工厂,工厂类做成单例.
例4:web服务器中的token随机数生成器(给表单设置一个唯一 id)也是单例.
ps:总之就是只需要用一个实例时,都可以使用单例.
二、工厂模式
建立一个工厂类,对实现了同一接口的一些类进行实例的创建,减少代码中大量的new,解耦合.spring的bean工厂,典型的大大的工厂模式.
//单例,工厂
public class ServiceFactory {
private Properties serviceConfig = new Properties();
//单例的构造函数也只执行一次
private ServiceFactory(){
InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("service.properties");
try {
serviceConfig.load(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static ServiceFactory instance = new ServiceFactory();
public static ServiceFactory getInstance(){
return instance;
}
public <T> T createService(Class<T> clazz){
//clazz.getName()拿到的带包名
String name = clazz.getSimpleName();
String className = serviceConfig.getProperty(name);
try {
T service = (T) Class.forName(className).newInstance();
return service;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
//service.properties
BusinessService=cn.itcast.service.impl.BusinessServiceImpl
BusinessService service = (BusinessService) ServiceFactory.getInstance().createService(BusinessService.class);
三、适配器模式(Adapter)
将一个类的接口转换成客户期望的另一个接口,让原本不兼容的接口可以合作无间.比如去德国手机充电问题.
http://www.cnblogs.com/wangjq/archive/2012/07/09/2582485.html 这个讲的比较好.
四、装饰模式(Decorator)
1、装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例.
2、装饰器模式的应用场景:
1>需要扩展一个类的功能.
2>动态的为一个对象增加功能,而且还能动态撤销.(继承不能做到这一点,继承的功能是静态的,不能动态增删.)
public interface Sourceable {
public void method();
}
public class Source implements Sourceable {
public void method() {
System.out.println("the original method!");
}
}
public class Decorator implements Sourceable {
private Sourceable source;
public Decorator(Sourceable source) {
this.source = source;
}
public void method() {
System.out.println("before decorator!");
source.method();
System.out.println("after decorator!");
}
}
public class DecoratorTest {
public static void main(String[] args) {
Sourceable source = new Source();
Sourceable obj = new Decorator(source);
obj.method();
}
}
ps:参见javaEE(12)_数据库连接池的第一种实现,目标是拦截close方法.其实给用户的数据库连接是经过我包装后的连接对象,感觉装饰模式可以被动态代理取代.
五、动态代理模式
1、代理模式的应用场景:如果已有的方法在使用的时候需要对原有的方法进行改进,和装饰模式要实现的目的一样,但是更简便,不拦截的方法无需一一写出来.
2、代理对象存在的价值:用于拦截对真实业务方法的访问,如在jdbc数据库连接池中使用动态代理拦截close方法,将连接放入连接池而不是关闭.
3、原理就是:实际用户拿到的连接是代理对象而不是正在的Connection对象,代理类实现InvocationHandler类.
http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
动态代理应用:
//1、jdbc数据库连接池中使用动态代理拦截close方法,将连接放入连接池而不是关闭:
public synchronized Connection getConnection() throws SQLException {
if(list.size()<=0){
throw new RuntimeException("数据库忙,请稍会再来!!");
}
Connection conn = list.removeFirst(); //list.get()不行
return new MyConnectionHandler(conn,this).getWarpConn();
}
class MyConnectionHandler implements InvocationHandler {
private Connection realConnection;
private Connection warpedConnection;
private MyDataSource dataSource;
private int maxUseCount = 5;
private int currentUserCount = 0;
MyConnectionHandler(Connection conn,MyDataSource dataSource) {
this.realConnection=conn;
this.dataSource = dataSource;
}
Connection getWarpConn() {
warpedConnection = (Connection) Proxy.newProxyInstance(this
.getClass().getClassLoader(), new Class[] { Connection.class },this);
return warpedConnection;
}
//proxy:把代理对象自身传递进来 method:代表当前调用的方法 args:调用方法的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("close".equals(method.getName())) {
currentUserCount++;
if (currentUserCount < maxUseCount)
dataSource.connectionsPool.addLast(warpedConnection);
else {
realConnection.close();
dataSource.currentCount--;
}
}
return method.invoke(realConnection, args);
}
}
//2、动态代理改写之前的解决全站乱码拦截器 *经典
public class CharacterEncodingFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
request.setCharacterEncoding("UTF-8"); // 解决post乱码
chain.doFilter((ServletRequest) Proxy.newProxyInstance(
CharacterEncodingFilter.class.getClassLoader(),
request.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) {
if (!method.getName().equals("getParameter")) {
return method.invoke(request, args);
}
if (!request.getMethod().equalsIgnoreCase("get")) {
return method.invoke(request, args);
}
String value = (String) method.invoke(request, args);
if (value == null) {
return null;
}
return new String(value.getBytes("iso8859-1"), "UTF-8");
}
}), response);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
//3、动态代理改写之前的压缩输出拦截器
public class GzipFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) resp;
ResponseProxy proxy = new ResponseProxy(response);
chain.doFilter(request, proxy.createProxy());
byte[] out = proxy.getBuffer(); // 得到目标资源的输出
System.out.println(new String(out, "UTF-8"));
}
class ResponseProxy {
private ByteArrayOutputStream bout = new ByteArrayOutputStream();
private PrintWriter pw = null;
public byte[] getBuffer() {
if (pw != null) {
pw.close();
}
return bout.toByteArray();
}
private HttpServletResponse response;
public ResponseProxy(HttpServletResponse response) {
this.response = response;
}
public HttpServletResponse createProxy() {
return (HttpServletResponse) Proxy.newProxyInstance(GzipFilter.class.getClassLoader(),
response.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args){
if (!method.getName().equals("getWriter")&&
!method.getName().equals("getOutputStream")) {
method.invoke(response, args);
}
if (method.getName().equals("getWriter")) {//PrintWriter.write("中国");
pw = new PrintWriter(new OutputStreamWriter(bout, "UTF-8"));
return pw;
}
if (method.getName().equals("getOutputStream")) {
return new ServletOutputStream() {
@Override
public void write(int b) throws IOException {
bout.write(b);
}
};
}
return null;
}
});
}
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
//4、动态代理+注解,实现权限管理
//service方法中,权限可精确到具体的方法
@Permission("添加分类")
public void addCategory(Category c){
cdao.add(c);
}
@Permission("查看分类")
public Category findCategory(String id){
return cdao.find(id);
}
public class ServiceFactory {
private ServiceFactory(){}
private static ServiceFactory instance = new ServiceFactory();
public static ServiceFactory getInstance(){
return instance;
}
public BusinessService createService(final User user){
final BusinessService service = new BusinessServiceImpl();
return (BusinessService) Proxy.newProxyInstance(ServiceFactory.class.getClassLoader(),
service.getClass().getInterfaces(), new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//得到web层调用的方法
String methodName = method.getName(); //addCategory
//反射出真实对象上相应的方法,检查真实对象方法上有没有权限注解
Method realMethod = service.getClass().getMethod(methodName,
method.getParameterTypes());
Permission permission = realMethod.getAnnotation(Permission.class);
if(permission==null){
return method.invoke(service, args);
}
//真实对象相应的方法上有权限注解,则得到访问该方法需要的权限
Privilege p = new Privilege(permission.value());//得到方法需要的权限
//检查用户是否有权限 //AppContext ThreadLocal
//得到用户所有权限
if(user==null){
throw new SecurityException("您没有登陆");
}
List<Privilege> list = service.getUserAllPrivilege(user);
if(list.contains(p)){
return method.invoke(service, args);
}
throw new SecurityException("你没有权限");
}
});
}
}
public class CategoryServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String method = request.getParameter("method");
if("add".equals(method)){
add(request,response);
}
if("getAll".equals(method)){
getAll(request,response);
}
}
private void getAll(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
BusinessService service = ServiceFactory.getInstance().
createService((User)request.getSession().getAttribute("user"));
try{
List list = service.getAllCategory();
request.setAttribute("categories", list);
request.getRequestDispatcher("/manager/listcategory.jsp").forward(request, response);
}catch (Exception e) {
if(e.getCause() instanceof SecurityException){
request.setAttribute("message", e.getCause().getMessage());
}
}
}
private void add(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
BusinessService service = ServiceFactory.getInstance().
createService((User)request.getSession().getAttribute("user"));
try {
Category c = WebUtils.request2Bean(request, Category.class);
c.setId(UUID.randomUUID().toString());
service.addCategory(c);
request.setAttribute("message", "添加成功");
} catch (Exception e) {
if(e.getCause() instanceof SecurityException){
request.setAttribute("message", e.getCause().getMessage());
}else{
e.printStackTrace();
request.setAttribute("message", "添加失败");
}
}
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
六、责任链模式
参见:struts2基础中拦截器的实现原理.
七、模板、策略模式
模板方法:在定义功能时,功能的一部分是确定的,一部分是不确定的,那么就可以将不确定的部分暴露出去,让子类去完成.
例:获取一段程序的执行时间
abstract class GetRuntime{
public final int getTime(){
int start = System.currentTimeMillis();
runCode();
int end = System.currentTimeMillis();
System.out.print(end - end)/1000;
}
abstract void runCode();
}
class Zi extends GetRuntime{
void runCode(...)
Zi z = new Zi();
z.getTime();
}
八、享元模式
java中常量池采用的就是享元设计模式,实际中做缓存时会采会用hashMap做一个享元,有的话直接拿,没有的话创建拿了再放进去.
九、外观模式
例如:service层的接口,封装所有的下层细节,对外暴漏简单的接口,这就是外观模式.