设计模式类别:
java的设计模式大体上分为三大类:
- 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。一种对象创建型模式,它可以将复杂对象的建造过程抽象出来(抽象类别)抽象类、接口,使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
建造者模式意在为重叠构造器这种反模式(telescoping constructor anti-pattern)找到一种解决方案 - 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式(队列、栈),桥接模式,组合模式,享元模式。这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
- 行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。这些设计模式特别关注对象之间的通信。
设计模式遵循的原则有6个:
1、开闭原则(Open Close Principle)
对扩展开放,对修改关闭。
2、里氏代换原则(Liskov Substitution Principle)
只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1代换o2时,程序P的行为没有变化,那么类型S是类型T的子类型。在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
使用多个隔离的接口来降低耦合度。
5、迪米特法则(最少知道原则)(Demeter Principle)
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类的封装性,超类的方法可能会被子类修改。
参考网址:https://blog.csdn.net/alinshen/article/details/79502098
https://www.cnblogs.com/malihe/p/6891920.html
常用设计模式:
工厂模式(Factory Method)
工厂模式属于创建型设计模式,它提供了一种创建对象的最佳方式。隐藏复杂的逻辑处理过程, 只关心执行结果。直接用new可以完成的不需要用工厂模式.需要生成复杂对象的地方使用。
简单工厂模式 功能强大,但是可扩展性不强
1,定义接口
public interface SoftwareTechnology {
void study();
}
2,编写实现类
public class JavaDevelop implements SoftwareTechnology {
@Override
public void study() {
// TODO Auto-generated method stub
System.out.println("经过了努力,学会了JAVA");
}
}
public class PythonDevelop implements SoftwareTechnology {
@Override
public void study() {
// TODO Auto-generated method stub
System.out.println("经过了努力,学会了 Python");
}
}
3,创建工厂
public class AAAFactory {
public SoftwareTechnology studyST(int code){
if(code==1){
return new JavaDevelop();
}else if(code==2){
return new PythonDevelop();
}else{
return null;
}
}
}
4,测试
public static void main(String[] args) {
SoftwareTechnology javaDevelop = new AAAFactory().studyST(1);
javaDevelop.study();
SoftwareTechnology PythonDevelop = new AAAFactory().studyST(2);
PythonDevelop.study();
}
工厂方法:独立分工,可以不断开分厂:简单工厂模式:不同的技术需要不同额外参数的时候 不支持。违背开闭原则
1,定义工厂接口
public interface GBFactory {
SoftwareTechnology studySt();
}
2,编写工厂实现类
public class ZhiYouFactory implements GBFactory {
@Override
public SoftwareTechnology studySt() {
// TODO Auto-generated method stub
return new JavaDevelop();
}
}
public class ChuanZhiFactory implements GBFactory {
@Override
public SoftwareTechnology studySt() {
// TODO Auto-generated method stub
return new BigDataDevelop();
}
}
3,测试
public static void main(String[] args) {
// TODO Auto-generated method stub
GBFactory factory=new ChuanZhiFactory();
factory.studySt().study();
}
抽象工厂,简单工厂和工厂方法的结合体
1,定义抽象接口(包括简单和工厂方法)
public abstract class AbstractFactory {
abstract SoftwareTechnology studySt();
public SoftwareTechnology studyST(int code){
if(code==1){
return new JavaDevelop();
}else if(code==2){
return new PythonDevelop();
}else{
return new BigDataDevelop();
}
}
}
2,编写实现工厂
public class QianFengFactory extends AbstractFactory {
@Override
SoftwareTechnology studySt() {
// TODO Auto-generated method stub
return new PythonDevelop();
}
}
3,测试两种方式
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractFactory af=new QianFengFactory();
af.studySt().study();
af.studyST(1).study();
}
单例(态)模式(Singleton)
一种常用的软件设计模式。所谓单例,就是让一个类在项目中只存在一个对象,即使用到这个类的地方很多,也只存在一个对象。
好处:节省内存,有些情况下不用单例模式可能会引起代码逻辑错误(例如:网站访问量统计功能)。
单例模式要点
1. 是单例模式的类只提供私有的构造函数;
2. 是类定义中含有一个该类的静态私有对象;
3. 是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象;
实现方式:
懒汉:(starving)该单例类非常懒,只有在自身需要的时候才会行动,从来不知道及早做好准备。特点是运行时获得对象的速度比较慢,但加载类的时候比较快。整个应用的生命周期只有一部分时间在占用资源。
Classs SingTon{
private SingleTon(){}//保证了只能在类内访问
private static SingleTon instance = null;
public static SingleTon getInstance(){
if(instance == null)
instance = new SingleTon(); //返回实例
return instance; //不为空,直接返回;
}
}
项目中,只有一个实例;有一个缺点,是多线程,不行。
饿汉:(slacker)该单例类非常饿,迫切需要吃东西,所以它在类加载的时候就立即创建对象。特点是加载类的时候比较慢,但运行时获得对象的速度比较快。从加载到应用结束会一直占用资源。
private SingleTon(){}
private final static SingleTon instance = new SingleTon();
public static SingleTon getInstance(){
return instance;
}
线程安全单例模式:上述的实现方式很容易会想到存在一个严重的缺陷,就是“非线程安全”。最简单的方式就是通过synchronized关键字来实现线程同步,但同步锁是比较耗费资源的,如果在程序中频繁地获取对象,这样的话效率就大大地降低了。所以说,在单例中添加同步锁的方法比较适用于对对象获取不是很频繁地情况。
private SingleTon(){}
private static SingleTon instance = null;
public static synchronized SingleTon getInstance(){
if(instance == null)
instance = new SingleTon();
return instance;
}
双重检验锁:使用同步块加锁的方法。又称其为双重检查锁,因为会有两次检查instance == null,一次是在同步块外,一次是在同步快内。为什么在同步块内还要检验一次,因为可能会有多个线程一起进入同步块外的if,如果在同步块内不进行二次检验的话就会生成多个实例了。
private SingleTon(){}
private static SingleTon instance = null;
public static SingleTon getInstance(){
synchronized(SingleTon.class){
if(instance == null){
instance = new SingleTon();
}
}
return instance;
}
代理模式(Proxy)
其特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理信息、过滤信息、把消息转发给委托类,以及事后处理信息等。
代理类对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
//举例说明为什么要用代理及好处
普通代理示例()
银行雇员代理用户执行相关银行服务
/**
*@className:Account.java
*@description:
*@author:zz
*@createTime:2017年12月5日上午8:54:34
*/
public interface Account {
/**
* 余额查询服务
*/
public void queryAccountMoney();
/**
* 更新账号的服务(取钱)
* @param num
*/
public void updateMoney(double num);
}
/**
*@className:User.java
*@description:委托类实现接口,执行正常服务
*@author:zz
*@createTime:2017年12月5日上午8:58:11
*/
public class User implements Account {
@Override
public void queryAccountMoney() {
// TODO Auto-generated method stub
System.out.println("查询余额服务!!!!!!!!");
}
@Override
public void updateMoney(double num) {
// TODO Auto-generated method stub
System.out.println("你取走了"+num+"钱。。。。。。。。。");
}
}
package com.aaa.proxy.service.impl;
import com.aaa.proxy.service.Account;
/**
*@className:Emp.java
*@description:代理类,提供委托类委托的相关服务
*@author:zz
*@createTime:2017年12月5日上午8:59:43
*/
public class Emp implements Account {
private User user;
public Emp(User user){
this.user=user;
}
@Override
public void queryAccountMoney() {
// TODO Auto-generated method stub
user.queryAccountMoney();
}
@Override
public void updateMoney(double num) {
// TODO Auto-generated method stub
System.out.println("事务开始。。。。");
user.updateMoney(num);
System.out.println("事务结束处理。。。。");
}
}
/**
*@className:EmpTest.java
*@description:
*@author:zz
*@createTime:2017年12月5日上午9:07:48
*/
public class EmpTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Emp emp =new Emp(new User());
emp.queryAccountMoney();
emp.updateMoney(1000);
}
}
JDK动态代理:
java.lang.reflect包下提供了一个Proxy类和一个Invocationhandler接口,用来完成动态代理。
Invocationhandler接口:
当我们通过代理对象调用一个方法时,这个方法的调用就会被转发为由Invocationhandler这个接口的invoke方法进行调用
Object invoke(Object proxy,Method method ,Object[] args)
参数:Object proxy:指被代理的对象
Method method: 要调用的方法
Object[] args: 方法调用时所需的参数
Proxy类:
该类提供了一个创建动态代理对象的方法。
static Object newProxyInstance(ClassLoader loader ,Class<?>[] interfaces,InvocationHandler h);
参数:ClassLoader loader:类加载器,定义了哪个ClassLoader对象来对生成的代理对象进行加载。
Class<?>[] interfaces: 代理类要实现的全部接口
InvocationHandler h: 表示代理对象要关联的InvocationHandler对象。
/**
*@className:EmpProxy.java
*@description:
*@author:zz
*@createTime:2017年12月5日上午9:24:33
*/
public class EmpProxy implements InvocationHandler {
//委托对象
private Object obj;
/**
* 绑定委托对象,并返回代理类
* @param obj
* @return
*/
public Object bind(Object obj){
this.obj=obj;
//返回代理类,绑定该类实现的所有接口
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
/**
* 利用InvocationHandler提供的invoke执行委托类里面的委托服务方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object tobj = null;//被代理的类型为Object基类
// TODO Auto-generated method stub
System.out.println(method.getName()+"..............");
if(method.getName().equals("queryAccountMoney")){
tobj=method.invoke(obj, args);
}else{
System.out.println("事务开始。。。。");
tobj=method.invoke(obj, args);
System.out.println("事务结束处理。。。。");
}
return tobj;
}
}
CGLIB代理:
主要应用于没有接口的动态代理生成(主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。),AOP框架Hibernate都使用了CGLLIB。
net.sf.cglib.proxy.Enhancer类:允许为非接口类型创建一个Java代理。Enhancer动态创建了给定类型的子类拦截了所有的方法。(setSuperclass,setCallback,create)
net.sf.cglib.proxy.Callback接口:在CGLIB包中是一个很关键的接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口。
举例说明回调:
net.sf.cglib.proxy.MethodInterceptor接口:是最通用的回调(callback)类型,它经常被AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法。
public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy)
proxy:代理的对象;method:委托类执行的方法;params:方法中的参数; methodProxy:代理的方法
由于性能的原因,对原始方法的调用我们使用CGLIB的net.sf.cglib.proxy.MethodProxy对象,而不是反射中一般使用java.lang.reflect.Method对象
实现代码:
/**
*@className:EmpDao.java
*@description:
*@author:zz
*@createTime:2017年12月5日上午10:39:22
*/
public class EmpDao {
/**
* 员工添加操作
* @return
*/
public int add(){
System.out.println("执行员工添加操作。。。。。。。");
return 1;
}
}
/**
*@className:EmpDaoProxy.java
*@description:
*@author:zz
*@createTime:2017年12月5日上午10:44:14
*/
public class EmpDaoProxy implements MethodInterceptor {
//需要代理的类 (委托类)
private Object obj;
/**
* 把委托类拿过来
* @param obj
* @return
*/
public void bind(Object obj){
this.obj=obj;
}
/**
* 1、代理对象;2、委托类方法;3、方法参数;4、代理方法的MethodProxy对象。
*/
@Override
public Object intercept(Object proxy, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("打开事务。。。。。。");
Object invokeSuper = arg3.invokeSuper(proxy, arg2);//调用了原来的方法(通过代理类调用父类中的方法 )
System.out.println("提交事务。。。。。。");
return invokeSuper;
}
public Object getCGlibObject(){
//Enhancer允许为非接口类型创建一个Java代理。
Enhancer enhancer = new Enhancer();
// cglib创建的代理类是委托类的子类
enhancer.setSuperclass(obj.getClass());
//回调为当前类拦截的所有方法 this 必须实现MethodInterceptor接口
enhancer.setCallback(this);
//创建委托类子类对象
return enhancer.create();
}
}
/**
*@className:EmpDaoProxyTest.java
*@description:
*@author:zz
*@createTime:2017年12月5日上午11:10:18
*/
public class EmpDaoProxyTest {
public static void main(String[] args) {
EmpDaoProxy empDaoProxy =new EmpDaoProxy();
empDaoProxy.bind(new EmpDao());
EmpDao empDao = (EmpDao)empDaoProxy.getCGlibObject();//多态
int add = empDao.add();
}
}
如果目标对象没有实现接口,则默认会采用CGLIB代理;
如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。
CGLib动态代理创建代理实例速度慢,但是运行速度快;JDK动态代理创建实例速度快,但是运行速度慢。如果实例是单例的,推荐使用CGLib方式动态代理,反之则使用JDK方式进行动态代理。Spring的实例默认是单例,所以这时候使用CGLib性能高。
本文暂时没有评论,来添加一个吧(●'◡'●)