设计模式
1.设计模式是什么?设计模式的作用?
设计模式:
是一套反复被使用,多数人知晓的,经过分类的,代码设计经验的总结。
设计模式的作用:
为了代码的可重用性,让代码更容易被人理解,保证代码的可靠性,设计模式是编写代码真正工程化,设计模式是软件设计的基础。
2.单例模式的两种表示方式以及区别?
单例设计模式的一般定义:一个类中只允许有一个实例。
通常情况下我们的类可以创建出若干个实例【对象】,通过new 就可以完成,如果是单例模式构造的java类,那么他就只能由一个实例【对象】。
实现思路:让类的构造方法私有化【private】,同时提供一个静态方法[static]去实例化这个类。
单例模式有两种写法,懒汉式写法和饿汉式写法。
懒汉式:在静态方法中初始化。时间换空间。(不推荐,时间很重要)
package demo_singleton;
/*懒汉式的单例模式,有线程安全问题,当多线程访问的时候,会出现多个实例*/
public class SingletonLazy {
private static SingletonLazy instance = null;
public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
private SingletonLazy() {
}
}
饿汉式:在声明对象就初始化。空间换时间。(推荐,空间不是问题)
package demo_singleton;
public class SingletonHungry {
private static SingletonHungry singletonhunary = new SingletonHungry();
public static SingletonHungry getinstance() {
return singletonhunary;
}
private SingletonHungry() {
}
}
懒汉与饿汉比较:
懒汉式:是在得到本类对象的静态方法中创建的本类对象
饿汉式:是在定义本类对象的变量时就创建好了本类对象
从程序的运行速度角度分析:饿汉式的单例模式要比懒汉式的单例模式更快一些。
从程序的内存使用角度分析:懒汉式的单例模式要比饿汉式的单例模式更节省内存一些。
以后我们在构造自己的程序是如果需要某一个java类的对象在整个程序中只有一个对象的话,那么我们首先要想到的就是单例模式。
3.简单工厂模式的角色,编写简单工厂模式?
简单工厂设计模式的一般定义:简单工厂又叫静态工厂,由一个工厂对象决定创建哪一个产品对象。
实现思路:写一个类,让他制造出我们想要的对象。
抽象产品角色,工厂角色,具体产品角色
例如:有一个农场负责生产各种水果,有苹果,有草莓,有葡萄。
农场----工厂角色【java类】
水果---抽象产品角色【抽象类/接口】
苹果,草莓,葡萄----具体产品角【java类与抽象产品角色有继承/实现关系】
实例:
public abstract class Product {
public Product() {
}
}
每个具体的产品需要继承上面那个抽象类,一下依次为船,车,飞机类。通过简单的输出完成我们建造交通工具的梦想.
public class Boat extends Product {
public Boat() {
System.out.println("建造小船");
}
}
public class Car extends Product {
public Car() {
System.out.println("建造汽车");
}
}
public class Plane extends Product {
public Plane() {
System.out.println("建造飞机");
}
}
工厂类中有一个判断的方法,对用户的需求做出判断,实例化哪个对象
package demo_samplefactory;
public class Factory {
public Factory() {
}
public Product create(String product) {
if (product.equals("飞机")) {
return new Plane();
}
if (product.equals("小船")) {
return new Boat();
}
if (product.equals("汽车")) {
return new Car();
}
return null;
}
}
通过这个工厂,我们可以很方便的生产出我们想要的对象。
4.代理模式的分类?比较
代理模式的定义:
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式存在的意义:
降低了真实对象和要做事情的耦合性,降低了他们之间的联系,代理类对请求进行过滤,预处理,将请求交给真实对象,或者委派给真实对象。好比消费者不会去工厂去买产品,一个歌手不会每天都会接收到很多没有用的信息。
同样代理模式也符合开闭原则,对修改关闭,对扩展开放。在不改变真实类的情况下,对其类进行扩展。代理类对外提供一系列的接口,用户对其使用不会对原对象产生影响,对原对象有一个良好的封装性。
代理模式分为静态代理和JDK动态代理,还有一种是Cglib代理。
抽象角色:是一个接口,定义了行为,没有具体实现
public interface AbstractSubject {
public abstract void sing();
}
代理角色:其中有真实对象的引用,从而对真实对象进行操作,可以对真实对象的操作进行扩展,不会修改原对象
public class ProxySubject implements AbstractSubject {
private AbstractSubject abstractSubject;
public ProxySubject(AbstractSubject abstractSubject) {
this.abstractSubject = abstractSubject;
}
@Override
public void sing() {
abstractSubject.sing();
}
}
真实对象:有对事件的真实操作,最终我们要引用的对象。
public class RealSubject implements AbstractSubject{
@Override
public void sing() {
System.out.println("真唱");
}
}
测试类:
public class Test {
public static void main(String[] args) {
RealSubject reaal = new RealSubject();
ProxySubject proxy = new ProxySubject(reaal);
proxy.sing();
}
}
JDK动态代理:
动态代理相比于静态代理,动态代理的代理类是在动态生成的,也就是jvm通过反射获取代码生成代理类,所以用户并不能决定代理角色和真实角色之间的联系,而是由程序运行时候决定的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。
动态代理实现的三步走:
1.实现InvocationHandler接口,创建自己的调用处理器 。
2.给Proxy类提供ClassLoader和代理接口类型数组创建动态代理类 。
3.执行真实角色具体任务。
要想创建处理器必须实现InvocationHandler接口,之后通过类装载器创建代理类。每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy:指代我们所代理的那个真实对象
method:指代的是我们所要调用真实对象的某个方法的Method对象
args:指代的是调用真实对象某个方法时接受的参数
看上去实现很简单,我们只需要实现接口,调用其中的方法就可以实现动态代理。
通过newProxyInstance方法获取代理类实例,而后我们便可以通过这个代理类实例调用代理类的方法,对代理类的方法的调用实际上都会调用中介类(调用处理器)的invoke方法。
注意:JDK动态代理只能处理有接口实现关系的java类
Cglib代理
cglib是一个强大的高性能的代码生成包,广泛的被许多AOP的框架使用,它的开源地址在https://github.com/cglib/cglib
通过它实现动态代理,主要用到import net.sf.cglib.proxy包下的MethodInterceptor、MethodProxy和Enhancer类
(1)、MethodInterceptor
MethodInterceptor类是方法拦截器,代理类实例的方法被调用时会回调MethodInterceptor的intercept()方法拦截,用来实现自己的代理逻辑,类似于jdk动态代理的InvocationHandler接口
(2)、MethodProxy
MethodProxy是intercept()方法中的第四个参数的类型,它是实际类方法的代理引用,使用methodProxy比使用jdk自身的method在效率上会有提升
(3)、Enhancer
Enhancer用来动态创建实际类子类的代理类实例,setSuperclass()方法设置实际类为父类,setCallback()方法建立方法回调,create()方法创建一个代理类实例
比较
1.静态代理是通过在代码中显式定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法;
手动创建一个与目标类相同接口的子类,包装目标类。
2.JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;【兄弟模式】
通过jdk提供的反射包中Proxy这个类,动态的创建一个与目标类实现相同接口的子类对象,包装目标。
3.CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理。【父子模式】
通过CGlib提供的Enhancer这个类,动态的创建一个目标类的子类对象,包装目标类。