目录
OPP七大原则
创建型模式
单例设计模式
工厂模式
结构型模式
代理设计模式
行为型模式
待更。。
控制对象实例化产生个数的设计操作。核心:构造方法私有化。Single类只允许产生一个实例化对象。
过程:
1、Single的构造方法私有化。
2、在Single中定义该类的实例化对象,并封装,并使用final确保只能实例化一次。sychronized和volatile多线程中保证安全。
3、定义一个static方法用于外部获取该实例化。
代码如下:饿汉式,系统加载就进行实例化。
class Singleton {
private Singleton (){} ;
private static final Singleton INSTANCE = new Singleton () ;
public static Singleton getInstance() {
return INSTANCE ;
}
}
懒汉式,第一次使用实例化。
class Singleton {
private Singleton (){} ;
private static final Singleton INSTANCE = null ;
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton () ;
}
return INSTANCE;
}
}
考虑多线程:使用synchronized实现同步
class Singleton {
private Singleton (){} ;
private static final Singleton INSTANCE = null ;
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized(Singleton.class){
if(INSTANCE == null){
INSTANCE = new Singleton() ;
}
}
}
return INSTANCE;
}
}
为什么还要做一次判空?
如果没有第二次判空,线程A与线程B同时过了第一次判空,那么虽然只能一个线程进入同步代码,但最终还是会实例化两次。
但是这个代码还是有问题,由于指令重排可能导致返回的结果没有初始化(参考链接:https://zhuanlan.zhihu.com/p/33102022)
instance = new Singleton(),会被编译器编译成如下JVM指令:
memory =allocate(); //1:分配对象的内存空间
ctorInstance(memory); //2:初始化对象
instance =memory; //3:设置instance指向刚分配的内存地址
但是这些指令顺序并非一成不变,有可能会经过JVM和CPU的优化,指令重排成下面的顺序:
memory =allocate(); //1:分配对象的内存空间
instance =memory; //3:设置instance指向刚分配的内存地址
ctorInstance(memory); //2:初始化对象
当线程A执行完1、3的时候,只分配内存未初始化,instance不为空;此时线程B进入第一次判空,不为空,直接到return代码,可以发现得到的是未初始化的instance。该问题通过volatile关键字解决。
volatile:不是用副本直接操作原始变量,具体查看:https://blog.csdn.net/qq_34949782/article/details/106127981#volatile%E5%85%B3%E9%94%AE%E5%AD%97
最终代码:
class Singleton {
private Singleton (){} ;
private volatile static final Singleton INSTANCE = null ;
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized(Singleton.class){
if(INSTANCE == null){
INSTANCE = new Singleton() ;
}
}
}
return INSTANCE;
}
}
将对象的创建封装到一种称为「工厂」的类中,从调用方角度来看,需要「产品」时,不需要亲自 new 出来,通过调用工厂对象的方法就可以得到对象。能够将对象的创建和使用相分离,从而减少类之间的耦合度,提高复用性。
参考连接:https://blog.csdn.net/qq_34949782/article/details/105952800
参考连接:https://blog.csdn.net/qq_34949782/article/details/106269445(利用反射为所有接口服务)
参考连接:https://blog.csdn.net/qq_34949782/article/details/106301186
静态工厂模式:
package cn.ren.demo;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
IMessage msg = Factory.getInstance("netmessage") ;
msg.send();
}
}
interface IMessage {
public void send() ; // 消息发送
}
class NetMessage implements IMessage {
public void send () {
System.out.println("【网络消息发送】ren");
}
}
class Factory {
private Factory() {} // 没有产生实例化的意义,所以构造方法私有化
public static IMessage getInstance (String className) {
if ("netmessage".equals(className)) {
return new NetMessage() ;
}
return null;
}
}
随着项目的进行,你的IMesagel类有可能会有更多的子类,而且随着时间的推移子类产生越来越多,这就意味着你的工厂类永远你都要进行修改。那么这个时候最好的解决方案就是不使用关键字new来完成,因为关键字new在使用的时候需要有一个明确的类存在。而newInstance()的方法只需要一个明确表示类名称的字符串即可应用。
package cn.ren.demo;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
IMessage msg = Factory.getInstance("cn.ren.demo.NetMessage") ;
msg.send();
}
}
interface IMessage {
public void send() ; // 消息发送
}
class CloudMessage implements IMessage {
@Override
public void send() {
System.out.println("【云消息】57");
}
}
class NetMessage implements IMessage {
public void send () {
System.out.println("【网络消息发送】ren");
}
}
class Factory {
private Factory() {} // 没有产生实例化的意义,所以构造方法私有化
public static IMessage getInstance (String className) {
IMessage instance = null ;
try {
instance = (IMessage) Class.forName(className).getDeclaredConstructor().newInstance() ;
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
}
为项目的实际开发过程之中,有可能会存在大量的接口,并且这些接口,都可能需要通过工厂类实例化,以此时的工厂设计模式不应该只为了一个IMessage接口服务,应该为所有的接口服务。只能依赖泛型,如下:
package cn.ren.demo;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
IMessage msg = Factory.getInstance("cn.ren.demo.NetMessage", IMessage.class) ;
msg.send();
IService service = Factory.getInstance("cn.ren.demo.HouseService", IService.class) ;
service.service();
}
}
interface IService {
public void service() ;
}
class HouseService implements IService {
public void service() {
System.out.println("【服务】为你的住宿提供服务");
}
}
interface IMessage {
public void send() ; // 消息发送
}
class NetMessage implements IMessage {
public void send () {
System.out.println("【网络消息发送】ren");
}
}
class Factory {
private Factory() {} // 没有产生实例化的意义,所以构造方法私有化
/**
* 获取接口实例化对象
* @param
* @param className 接口的子类
* @param clazz 描述一个接口的类型
* @return 如果子类存在返回接口实例化对象
*/
@SuppressWarnings("unchecked")
public static T getInstance (String className, Class clazz) {
T instance = null ;
try {
instance = (T) Class.forName(className).getDeclaredConstructor().newInstance() ;
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
}
利用Annotation实现子类的更换
package cn.ren.demo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
MessageService messageService = new MessageService() ;
messageService.send("ren");
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface UseMessage {
public Class> clazz() ;
}
@UseMessage(clazz=MessageImpl.class) // 利用Annotation实现类的使用,以后换子类时Annotation更换就完成了。例如clazz=NetMessageImpl.class;
class MessageService {
private IMessage message ;
public MessageService() {
UseMessage use = MessageService.class.getAnnotation(UseMessage.class) ;
this.message = (IMessage) Factory.getInstance(use.clazz()) ; // 直接是通过Annotation获取
}
public void send(String msg) {
this.message.send(msg);
}
}
class Factory {
private Factory() {}
@SuppressWarnings("unchecked")
public static T getInstance(Class clazz) { // 直接返回一个实例化的操作对象
try {
return (T) new MessageProxy().bind((clazz.getDeclaredConstructor().newInstance())) ;
} catch (Exception e) {
e.printStackTrace();
return null ;
}
}
}
class MessageProxy implements InvocationHandler {
private Object target ;
public Object bind(Object target) {
this.target = target ;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this) ;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object returnData = null;
try {
if (this.connect()) {
returnData = method.invoke(this.target, args);
} else {
throw new Exception("【ERROR】消息无法发送");
}
} finally {
this.close();
}
return returnData;
}
public boolean connect() {
System.out.println("【代理】发送通道建立");
return true ;
}
public void close() {
System.out.println("【代理】发送通道关闭");
}
}
interface IMessage {
public void send(String msg) ;
}
class MessageImpl implements IMessage {
@Override
public void send(String msg) {
System.out.println("【消息发送】" + msg);
}
}
代理设计的主要功能是可以帮助用户将所有开发的注意力集中在核心业务处理上。代理设计模式的主要特点有:一个接口提供有两个子类,其中一个子类是真实业务操作类,另外一个主题是代理业务操作类,没有代理业务操作真实业务无法进行。
静态代理设计的特点在于:一个代理类只为一个接口服务。参考连接:https://blog.csdn.net/qq_34949782/article/details/106301186
package cn.ren.demo;
interface IMessage { // 传统代理设计必须有接口
public void send(); // 业务方法
}
class MessageReal implements IMessage {
public void send() {
System.out.println("【发送消息】 ren57");
}
}
class MessageProxy implements IMessage {// 代理类
private IMessage message ; // 代理对象,一定是业务接口实例
public MessageProxy(IMessage message) {
this.message = message ;
}
@Override
public void send() {
if (this.connect()) {
this.message.send();
this.close();
}
}
public boolean connect() {
System.out.println("【消息代理】进行消息发送通道的连接");
return true ;
}
public void close() {
System.out.println("【消息代理】关闭消息通道");
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
IMessage msg = new MessageProxy(new MessageReal()) ;
msg.send();
}
}
以上的代理设计模式为静态代理设计,这种静态代理设计的特点在于:一个代理类只为一个接口服务。那么如果现在准备出了3000个业务接口,按照此种做法就需要编写3000个代理类,并且这3000个代理类操作形式一样。
通过静态代理设计模式的缺陷可以发现,最好的做法是为所有功能一致的业务操作接口提供统一的代理处理操作,这样就可以通过动态代理机制来实现,但是在动态代理机制里面需要考虑到如下几点问题:
在进行动态代理的实现过程之中,首先需要关注的就是一个InvocationHandler接口。接口中定义invoke()方法,这个接口规定了代理方法的执行。
public interface InvocationHandler {
/**
* 代理方法调用,代理主题类里面执行的方法最终都是此方法
*
* @param proxy 要代理的对象
* @param method 要执行的接口方法名称
* @param args 传递的参数
* @return 某一个方法的返回值
* @throws Throwable 方法调用时出现的错误,继续向上抛出。
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
在进行动态代理设计的时候动态对象的创建是由JVM底层完成的,此时主要依靠的时java.lang.reflect.Proxy程序类,这个程序类之中只提供有一个核心方法:
| - ClassLoader loader: 获取当前真实主体类的ClassLoader;
|- Class> [] interfaces :代理时围绕接口进行的,所以一定要获取真实主题类的接口信息;
|- InvocationHandler h :代理处理的方法;
package cn.ren.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
IMessage msg = (IMessage) new RENProxy().bind(new MessageReal()) ;
msg.send();
}
}
class RENProxy implements InvocationHandler {
private Object target ; // 保存真实业务主题对象
/**
* 进行真实业务对象与代理业务对象绑定处理
* @param target 真实业务对象
* @return Proxy生成的代理业务对象
*/
public Object bind(Object target) {
this.target = target ;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this) ;
}
public boolean connect() {
System.out.println("【消息代理】进行消息发送通道的连接");
return true ;
}
public void close() {
System.out.println("【消息代理】关闭消息通道");
}
public Object invoke(Object pro, Method method, Object[] args) throws Throwable {
System.out.println("************【执行方法】" + method);
Object returnData = null ;
if (this.connect()) {
returnData = method.invoke(this.target,args) ;
this.close();
}
return returnData ;
}
}
interface IMessage { // 传统代理设计必须有接口
public void send(); // 业务方法
}
class MessageReal implements IMessage {
@Override
public void send() {
System.out.println("【发送消息】 ren57");
}
}
CGLIB实现代理设计模式
从Java的官方来讲已经明确了如果要想实现代理设计模式,一定是基于接口的应用,所在在官方给出的Proxy类创建代理对象时都需要传递该对象所有的接口信息。
但是这个时候有一部分的开发者就认为不应该强迫性的基于接口来实现代理设计,所以开发者就开发出了一个CGLIB的开发包,利用这个开发包就可以实现基于类的代理设计模式。