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();
}
八、享元模式
java中常量池采用的就是享元设计模式,实际中做缓存时会采会用hashMap做一个享元,有的话直接拿,没有的话创建拿了再放进去.
九、外观模式
例如:service层的接口,封装所有的下层细节,对外暴漏简单的接口,这就是外观模式.
java设计模式基础 - 解决某一类问题最行之有效的方法,框架是大的设计模式.的更多相关文章
- [零基础学JAVA]Java SE基础部分-03.标识符、数据类型,数组,方法
运算符 注意布尔逻辑运行: &&(短路与) 各 &的区别: &&只要判断到一项为0,则后面不判断.&,两项都要判断 ||(短路或)和 |的区别: 同 ...
- java设计模式--基础思想总结--父类引用操作对象
看设计模式的相关书籍也有一段时间了,一开始其实是抱着作为java三大框架的基础知识储备来学习的,不过到后来,才发现,在设计模式的一些准则装饰下,java的面向对象威力才真正地体现出来,后面的将会陆续地 ...
- java中文乱码解决之道(二)-----字符编码详解:基础知识 + ASCII + GB**
在上篇博文(java中文乱码解决之道(一)-----认识字符集)中,LZ简单介绍了主流的字符编码,对各种编码都是点到为止,以下LZ将详细阐述字符集.字符编码等基础知识和ASCII.GB的详情. 一.基 ...
- java中文乱码解决之道(二)—–字符编码详解:基础知识 + ASCII + GB**
原文出处:http://cmsblogs.com/?p=1412 在上篇博文(java中文乱码解决之道(一)—–认识字符集)中,LZ简单介绍了主流的字符编码,对各种编码都是点到为止,以下LZ将详细阐述 ...
- java必备基础知识点
Java基础 1. 简述Java的基本历史 java起源于SUN公司的一个GREEN的项目,其原先目的是:为家用消费电子产品发送一个信息的分布式代码系统,通过发送信息控制电视机.冰箱等 2. 简单写出 ...
- 【重走Android之路】【Java面向对象基础(三)】面向对象思想
[重走Android之路][基础篇(三)][Java面向对象基础]面向对象思想 1 面向对象的WWH 1.1 What--什么是面向对象 首先,要理解“对象”.在Thinkin ...
- JAVA学习基础知识总结(原创)
(未经博主允许,禁止转载!) 一.基础知识:1.JVM.JRE和JDK的区别: JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性. java语言是跨平 ...
- JAVA面试基础
JAVA相关基础知识1.面向对象的特征有哪些方面 ?1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂 ...
- [ Java学习基础 ] Java的继承与多态
看到自己写的东西(4.22的随笔[ Java学习基础 ] Java构造函数)第一次达到阅读100+的成就还是挺欣慰的,感谢大家的支持!希望以后能继续和大家共同学习,共同努力,一起进步!共勉! ---- ...
随机推荐
- laravel定义全局变量并输出(实例)
在config目录创建一个 bl.php ,内容如下 <?php return [ 'IND' => "1321232", 'das' => "奥术大师 ...
- laravel SQL语句
DB::table('表名')->get(); //查询表里的所有数据 DB::table('表名')->where()->find(需要查询的条数); 查询单或多条数据 ...
- 爬虫—使用Requests
一,安装 pip install requests 二,基本用法 1.简单示例 import requests res = requests.get('https://www.baidu.com') ...
- element-ui + el-dialog + Vue.component 注册的富文本控件 第二次及以后打开dialog出现问题解决方法
自定控件 添加属性 v-if="dialogVisible" <el-dialog title="" :visible.sync="dialo ...
- properties 文件注意事项
不要使用""双引号包裹内容 db.validationQuery="select 1"比如上面这种是错误的,下面的是正确的写法 db.validationQue ...
- Zynq7000开发系列-2(VMware与Ubuntu安装使用)
一.前言 在嵌入式开发中,是无法避免使用Linux系统的,因为在开发之前必须先搭建起交叉编译环境,而后关于Bootloader.Linux Kernel的裁剪移植,File system的制作,底层驱 ...
- python 基础(四) 函数
函数 一.什么是函数? 函数是可以实现一些特定功能的 小方法 或者是小程序 优点: 提高 了代码的后期维护 增加了代码的重复使用率 减少了代码量 提高了代码可读性 二.函数的定义 使用 def关键+函 ...
- Codeforces Round #388 (Div. 2) D
There are n people taking part in auction today. The rules of auction are classical. There were n bi ...
- 洛谷 P4092 [HEOI2016/TJOI2016]树 || bzoj4551
https://www.lydsy.com/JudgeOnline/problem.php?id=4551 https://www.luogu.org/problemnew/show/P4092 这当 ...
- vue echarts 大小自适应
窗口大小时候 ,echarts图自适应 在创建图表的方法中直接,用resize方法 let myChart=this.$refs.myChart; let mainChart = echarts.in ...