架构设计
1. 什么是设计模式?
设计模式是在软件开发过程中面临一些问题的解决方案。设计模式是代码可用性的延伸。
设计模式分类:创建型模式,结构型模式,行为型模式
- 创建型模式:单例模式、工厂模式
- 结构型模式:代理模式、装饰器模式
- 行为型模式:观察者模式
2. 单例模式
在单例模式中,一个类只允许有一个实例对象。 可以通过懒汉式和饿汉式创建对象。
1. 懒汉式
- 定义一个私有的静态的该类的变量**,不要初始化,或者初始化为null**【懒汉式特点】
- 无参数构造方法声明私有, 这就使得外部无法通过构造函数创建这个类的对象了。
- 对外提供一个公共的静态的该类的访问方法,如果该变量为null,就创建对象,赋值给该变量。
public class Test{
private static Test t = null;
private Test(){
}
public static Test getTest(){
if(t == null){
t = new Test();
}
return t;
}
}
缺点:没有加锁,不支持多线程,线程不安全。
2. 懒汉式优化
为了实现线程安全,在对外提供的公共的静态的该类的方法上,加synchronized,即可。
public class Test{
private static Test t = null;
private Test(){}
public static synchronized Test getTest(){
if(t == null){
t = new Test();
}
return t;
}
}
3. 饿汉式
- 定义一个私有的静态的该类的变量,初始化该变量,也就是new一个该类对象,赋值给该变量。【饿汉式特点】
- 无参数构造方法声明为私有的,这样外部无法通过构造方法创建该类对象。
- 对外提供一个公共的静态的该类的访问方法,访问该变量。
public class Test{
private static Test t = new Test();
private Test(){
}
public static Test getTest(){
return t;
}
}
多线程安全:它基于 ClassLoder 机制避免了多线程的同步问题,所以线程安全
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,会创建很多无用的对象,浪费内存。
4. 饿汉式优化
我们需要用到该类对象时,才创建出来。因此,需要将该类的成员变量,放在一个私有的静态内部类中。静态类内部类不会因为外部类的加载而加载,在使用的时候才加载。
https://www.cnblogs.com/zouxiangzhongyan/p/10762540.html
public class Test{
private class innerClass{
private static Test t = new Test();
}
private Test(){
}
public static Test getTest(){
return innerClass.t;
}
}
其实通常了讲,就是资源的使用频率,高的我们在加载就实例化出来,低的就在使用的时候在实例化。
【补充】生产者和消费者什么意思。
静态代码块:在类加载的时执行,并且只执行一次,在main方法执行前执行。
作用:给java程序员提供了一个在main方法前执行的时间点,将不常用的代码可以写到静态代码块中。
https://blog.csdn.net/xlantian/article/details/80963640
5. 懒汉式 和 饿汉式 的区别
1、线程安全:
懒汉式是非线程安全的。
饿汉式就是线程安全的,可以直接用于多线程而不会出现问题,
2、资源加载和性能:
懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次调用时要做初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。
饿汉式在创建类的同时就实例化一个静态对象,不管之后会不会使用这个单例,都会占据一定的内存,但是相应的,在第一次调用时速度也会更快,因为其资源已经初始化完成。
原文链接:https://blog.csdn.net/qq_35098526/article/details/79893628
3. 工厂模式
其主要功能提取对象的实例化部分,目的是降低耦合度,提高扩展性。
1. 简单工厂模式
优点:将对象的创建和使用分离,将对象交给工厂类负责,降低耦合度,提高扩展性。
缺点:工厂类不够灵活,产品多,工厂代码复杂
//定义人类接口
public interface People{
public void say();
}
//定义男人类
public class Man implements People{
//实现接口say方法
public void say(){
System.out.println("Man");
}
}
//定义女人类
public class Women implements People{
//实现人类接口的say方法
public void say(){
System.out.println("Women");
}
}
//定义简单工厂类
public class Factory{
public People createPeople(String type){
if(type == null) return null;
if(type.equalsIgnoreCase("man")){
return new Man();
}else if(type.equalsIgnoreCase("women")){
return new Women();
}
}
}
//测试类
public class Test{
public static void main(String[] args){
//创建一个简单工厂对象
Factory f = new Factory();
Man man = f.createPeople("man");
man.say();
Women women = f.createPeople("women");
women.say();
}
}
2. 工厂方法模式
工厂方法模式是简单工厂模式的进一步抽象和推广。使用了面向对象的多态性。
在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是负责给出具体工厂必须实现的接口,并且将具体创建工作交给子类去做。符合面向对象编程的开闭原则[OCP]。
//定义人类接口
public interface People{
public void say();
}
//定义男人类
public class Man implements People{
public void say(){
System.out.println("Man");
}
}
//定义女人类
public class Women implements People{
public void say(){
System.out.println("Women");
}
}
//与简单工厂相比,工厂方法模式,给出具体实现接口
interface Factory{
People createPeople();
}
//工厂子类:男
public class FactoryMan implements Factory{
//实现Factory方法
public People createPeople(){
return new Man();
}
}
//工厂子类:女
public class FactoryWomen implements Factory{
//实现Factory方法
public People createPeople(){
return new Women();
}
}
//测试类
public class Test{
public static void main(String[] args){
//创建工厂:男
Factory f = new FactoryMan();
Man man = f.createPeople();
man.say();
//创建工厂:女
Factory f = new FactoryWomen();
Women women = f.createPeople();
women.say();
}
}
- 抽象工厂模式
https://www.jianshu.com/p/70f7fd47f2e2
4. 代理模式
1. 静态代理
静态代理其实就是在程序运行之前,提前写好被代理方法的代理类,编译后运行。在程序运行之前,class已经存在。
//定义人类接口
public interface People{
public void create();
}
//定义男人类
public class Man implements People{
public void create(){
System.out.println("Man");
}
}
//定义静态代理类
public class Proxy implements People{
private Proxy peoplePr;
public Proxy(People people){
this.peoplePr = people;
}
//实现People接口方法
public void create(){
peoplePr.create();
}
}
//测试类
public class Test{
public static void main(String[] args){
People people = new Man();
Proxy pr = new Proxy(people);
pr.create();
}
}
静态代理优缺点
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
2. JDK动态代理
从静态代理会发现——每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类。所以我们想办法通过一个代理类完成全部的代理功能,那么我们就需要用动态代理. 动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。
在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler
接口和 java.lang.reflect.Proxy
类的支持。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//定义人类接口
public interface People{
public void create();
}
//定义实现类
public class Man implements Peolpe{
public void create(){
System.out.println("Man");
}
}
//定义动态代理类
public class DynamicProxy implements InvocationHandler{
private DynamicProxy target;
public Object newProxyInstance(Object target){
this.target = target;
Object obj = Proxy.newProxyInstance(
target.getClass().getClassLoader,
target.getClass().getInterfaces(),this);
return obj;
}
//重写InvocationHandler的invoke()方法
public object invoke(Object obj,Method method,Object[] args) throws Throwable{
Object res = null;
try{
//调用目标方法
res = method.invoke(target,args);
}catch(Exception e){
e.printStackTrace();
}
return res;
}
}
//定义测试类
public class Test{
public static void main(String[] args){
//new一个动态代理
DynamicProxy dp = new DynamicProxy();
People p = (People)dp.newProxyInstance(new Man());
p.create();
}
}
动态代理的优缺点
- 优点
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke
)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强。 - 缺点
Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处——它始终无法摆脱仅支持 interface代理的桎梏,因为它的设计注定了这个遗憾。动态生成的代理类的继承关系图,已经注定有一个共同的父类叫 Proxy。Java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,原因是多继承在 Java 中本质上就行不通。
- GCLIB动态代理
https://www.cnblogs.com/daniels/p/8242592.html