设计模式
1. 设计模式是什么?设计模式的作用?
答:设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
设计模式的作用:为了代码的可重用性、让代码更容易被他人理解、保证代码的可靠性
2. 单例模式的两种表示方式以及区别?
答:懒汉模式:在静态方法中初始化。时间换空间(不推荐,时间很重要)。
懒汉式的单例模式有线程安全问题,当多线程访问的时候,会出现多个实例。
饿汉模式:在声明对象就初始化。空间换时间(推荐,空间不是问题)。
运行速度:饿汉模式比懒汉模式快。
空间利用率:懒汉模式比饿汉模式更节省空间。
3. 简单工厂模式的角色,编写简单工厂模式?
答:简单工厂模式一般定义:简单工厂又叫静态工厂,由一个工厂对象决定创建哪一个产品对象。
角色分为:抽象产品角色、工厂角色、具体产品角色。
实例:有一个农场负责生产各种水果,有苹果,有草莓,有葡萄。
package com.click369.test;
/**
* 水果接口--抽象产品角色
* @author Administrator
*
*/
public interface ShuiGuo {
public void eat();
}
package com.click369.test;
/**
* 葡萄类--具体产品角
* 抽象产品角色有继承/实现关系
* @author Administrator
*
*/
public class PuTao implements ShuiGuo{
@Override
public void eat() {
System.out.println("我吃的是葡萄");
}
}
package com.click369.test;
/**
* 草莓类--具体产品角
* 抽象产品角色有继承/实现关系
* @author Administrator
*
*/
public class CaoMei implements ShuiGuo{
@Override
public void eat() {
System.out.println("我吃的是草莓");
}
}
package com.click369.test;
/**
* 苹果类--具体产品角
* 抽象产品角色有继承/实现关系
* @author Administrator
*
*/
public class PingGuo implements ShuiGuo{
@Override
public void eat() {
System.out.println("我吃的是苹果");
}
}
package com.click369.test;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.HashMap;
/**
* 农场类--工厂角色
* 生产各种水果【苹果,草莓,葡萄】
* @author Administrator
*
*/
public class NongChang {
/**
* 读取菜单
* @return
*/
public static HashMap<String,String> getmenu(){
HashMap<String,String> menu=new HashMap<String,String>();
try {
File file=new File("menu.txt");
if(!file.exists()){
file.createNewFile();
}
BufferedReader readmenu=new BufferedReader(new FileReader(file));
String temp=null;
while((temp=readmenu.readLine())!=null){
String info[]=temp.split("=");
menu.put(info[0],info[1]);
}
readmenu.close();
}catch (Exception e) {
e.printStackTrace();
}
return menu;
}
/**
* 根据客户需求选择生产对应的水果
* @param shuiguoname
* @return
*/
public static ShuiGuo getShuiGuo(String shuiguoname){
ShuiGuo shuiguo=null;
try{
String classname=getmenu().get(shuiguoname);
if(classname==null || classname.equals("")){
shuiguo=null;
}
Class classobj=Class.forName(classname);
shuiguo=(ShuiGuo)classobj.newInstance();
}catch(Exception e){
e.printStackTrace();
}
return shuiguo;
}
}
Menu.txt
苹果=com.click369.test2.PingGuo
草莓=com.click369.test2.CaoMei
葡萄=com.click369.test2.PuTao
4. 代理模式的分类?比较?
答:代理模式分为:静态代理和动态代理
静态代理:让代理类继承目标类(父子模式)。
package com.click369.test;
/**
* 目标类--主要提供对学生信息的添加,删除,修改,查询
*
* @author Administrator
*
*/
public class StudentService {
public void addStudentInfo(){
System.out.println("完成添加学生信息的动作");
}
public void updateStudentInfo(){
System.out.println("完成修改学生信息的动作");
}
public void deleteStudentInfo(){
System.out.println("完成删除学生信息的动作");
}
public void selectStudentInfo(){
System.out.println("完成查询学生信息的动作");
}
}
package com.click369.test;
/**
* 代理类
* 基础目标类
* @author Administrator
*
*/
public class StudentServiceProxy extends StudentService{
public void savelog(){
System.out.println("记录日志");
}
@Override
public void addStudentInfo() {
super.addStudentInfo();
savelog();
}
@Override
public void updateStudentInfo() {
super.updateStudentInfo();
savelog();
}
@Override
public void deleteStudentInfo() {
super.deleteStudentInfo();
savelog();
}
@Override
public void selectStudentInfo() {
super.selectStudentInfo();
savelog();
}
}
让代理类实现与目标类相同的接口(兄弟模式)。
package com.click369.test;
public interface Service {
public void addStudentInfo();
public void updateStudentInfo();
public void deleteStudentInfo();
public void selectStudentInfo();
}
package com.click369.test;
/**
* 目标类--主要提供对学生信息的添加,删除,修改,查询
*
* @author Administrator
*
*/
public class StudentService implements Service{
public void addStudentInfo(){
System.out.println("完成添加学生信息的动作");
}
public void updateStudentInfo(){
System.out.println("完成修改学生信息的动作");
}
public void deleteStudentInfo(){
System.out.println("完成删除学生信息的动作");
}
public void selectStudentInfo(){
System.out.println("完成查询学生信息的动作");
}
}
package com.click369.test;
/**
* 代理类
* 基础目标类
* @author Administrator
*
*/
public class StudentServiceProxy implements Service{
public void savelog(){
System.out.println("记录日志");
}
@Override
public void addStudentInfo() {
System.out.println("完成添加学生信息的动作");
savelog();
}
@Override
public void updateStudentInfo() {
System.out.println("完成修改学生信息的动作");
savelog();
}
@Override
public void deleteStudentInfo() {
System.out.println("完成删除学生信息的动作");
savelog();
}
@Override
public void selectStudentInfo() {
System.out.println("完成查询学生信息的动作");
savelog();
}
}
静态代理的缺点:需要为每一个目标类单独创建一个代理类。
代理类中代码大部分是重复目标类中代码。
动态代理分为:JDK动态代理和Cglib动态代理。
动态代理的代理类是在动态生成的。也就是JVM通过反射获取代码生成代理类。
JDK动态代理只能处理有接口实现关系的java类。
package com.click369.test;
public interface Service {
public void addStudentInfo();
public void updateStudentInfo();
public void deleteStudentInfo();
public void selectStudentInfo();
}
package com.click369.test;
/**
* 目标类--主要提供对学生信息的添加,删除,修改,查询
*
* @author Administrator
*
*/
public class StudentService implements Service{
public void addStudentInfo(){
System.out.println("完成添加学生信息的动作");
}
public void updateStudentInfo(){
System.out.println("完成修改学生信息的动作");
}
public void deleteStudentInfo(){
System.out.println("完成删除学生信息的动作");
}
public void selectStudentInfo(){
System.out.println("完成查询学生信息的动作");
}
}
package com.click369.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 专门用来生成目标类的代理类对象的java类
* 1.实现InvocationHandler接口
* 2.重写InvocationHandler接口提供的invoke
* @author Administrator
*
*/
public class MyCreateProxyObjectClass implements InvocationHandler{
//定义一个目标类对象
private Object targetObject;
public MyCreateProxyObjectClass(Object targetObject){
this.targetObject=targetObject;
}
//得到一个代理类的对象
public Object getProxyObject(){
//第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
//第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
//第三个参数handler, 我 们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
private void savelog(){
System.out.println("记录日志");
}
/**
* proxy:指代我们所代理的那个真实对象
method:指代的是我们所要调用真实对象的某个方法的Method对象
args:指代的是调用真实对象某个方法时接受的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj=method.invoke(targetObject, args);
savelog();
return obj;
}
}
package com.click369.test;
public class TestMain {
public static void main(String[] args) {
//Service service=new StudentService();
//service.addStudentInfo();
StudentService service=new StudentService();
//创建代理类对象的java类对象
//需要一个目标类对象
MyCreateProxyObjectClass mcpc=new MyCreateProxyObjectClass(service);
//得到目标类的代理类对象
Service ser=(Service)mcpc.getProxyObject();
ser.addStudentInfo();
}
}
Cglib动态代理:
//被代理类
public class RealSubject {
public void Request() {
System.out.println("执行具体的功能");
}
public final void RequestFinal() {
System.out.println("执行具体的功能(final)");
}
}
//生成代理对象的java类
public class ProxyInterceptor implements MethodInterceptor {
public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib动态代理开始");
Object result = methodProxy.invokeSuper(proxy, params);
System.out.println("cglib动态代理开始");
return result;
}
//创建代理类实例
public Object newProxy(Object target)
{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
}
//测试类
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ProxyInterceptor proxyInterceptor = new ProxyInterceptor();
RealSubject subject = (RealSubject)proxyInterceptor.newProxy(realSubject);
subject.Request();
subject.RequestFinal();
}
}
比较:
- 静态代理是通过在代码中显示定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法。
手动创建一个与目标类相同接口的子类,包装目标类。
JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法(兄弟模式)。通过JDK提供的反射包中Proxy这个类,动态的创建与一个目标类实现相同接口的子类对象包装目标。
Cglib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理(父子模式)。
通过Cglib提供的Enhancer这个类,动态的创建一个目标类的子类对象,包装目标类。
5. 《大话设计模式》
《大话设计模式》是2007年清华大学出版社出版的图书,作者是程杰。本书中以情景对话的形式,用多个小故事或编程示例来组织讲解GoF总结的23个设计模式。