java设计模式基础

、单例模式(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();
} 

参见:javaEE(13)_jdbc框架

八、享元模式

java中常量池采用的就是享元设计模式,实际中做缓存时会采会用hashMap做一个享元,有的话直接拿,没有的话创建拿了再放进去.

参见:javase(7)_Objcet类

九、外观模式

例如:service层的接口,封装所有的下层细节,对外暴漏简单的接口,这就是外观模式.

原文地址:https://www.cnblogs.com/wangweiNB/p/5218144.html