文章目录

  • 1.建模语言(UML)
  • 1.1类
  • 1.2接口
  • 1.3UML类图
  • 1.4 类之间的关系
  • 2.面向对象语言的设计原则
  • 3.单例模式
  • 4.工厂模式
  • 5.代理模式
  • JDK代理
  • CgLib代理



1.建模语言(UML)

建模语言(Unified Modeling Language,UML)是用来设计软件蓝图的可视化建模语言,1997 年被国际对象管理组织(OMG)采纳为面向对象的建模语言的国际标准.

1.1类

指具有相同属性、方法和关系的对象的抽象,它封装了数据和行为,是面向对象程序设计(OOP)的基础,具有封装性、继承性和多态性等三大特性

  • (1) 类名(Name)是一个字符串,例如,Student。
  • (2) 属性(Attribute)是指类的特性,即类的成员变量。UML 按以下格式表示:[可见性]属性名:类型[=默认值]

“可见性”表示该属性对类外的元素是否可见
包括公有(Public)+私有(Private)-受保护(Protected)#,和关联(Friendly)~4 种.

  • (3) 操作(Operations)是类的任意一个实例对象都可以使用的行为,是类的成员方法。表示:[可见性]名称(参数列表)[:返回类型];

例如学生类:

java语言模型训练 java建模语言_代理模式


1.2接口

接口具有类的结构但不可被实例化,仅可以被子类实现。它包含抽象操作,但不包含属性。
它描述了类或组件对外可见的动作。
在 UML 中,接口使用一个带有名称的小圆圈来进行表示.

java语言模型训练 java建模语言_代理模式_02


1.3UML类图

用来显示系统中的类、接口、协作以及它们之间的静态结构和关系的一种静态模型
它主要用于描述软件系统的结构化设计,帮助开发者简化对软件系统的理解,
是系统分析与设计阶段的重要产物,也是系统编码与测试的重要模型依据。

其中的类可以通过某种编程 语言直接实现。类图在软件系统开发的整个生命周期都是有效的,它是面向对象系统的建模中最常见的图。

java语言模型训练 java建模语言_java_03


1.4 类之间的关系

依赖(Dependency)关系 是一种使用关系,它是对象之间耦合度最弱的一种关联方式,是临时性的关联。在代码中,某个类的方法通过局部变量、方法的参数或者对静态方法的调用来访问另一个类(被依赖类)中的某些方法来完成一些职责。

参数

例如人与手机之间就是依赖关系

java语言模型训练 java建模语言_java_04


关联(Association)关系对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系,如老师和学生、师傅和徒弟、丈夫和妻子等。关联关系是类与类之间最常用的一种关系,分为一般关联关系、聚合关系和组合关系。

在一个类中,把另一个类当做属性

关联可以是双向的,也可以是单向的。在 UML 类图中,双向的关联可以用带两个箭头或者没有箭头的实线来表示,单向的关联用带一个箭头的实线来表示,箭头从使用类指向被关联的类。也可以在关联线的两端标注角色名,代表两种不同的角色。

java语言模型训练 java建模语言_System_05


关联(Association)关系聚合(Aggregation)关系强关联关系,是整体和部分之间的关系,是 has-a 的关系。聚合关系也是通过成员对象来实现的,其中成员对象是整体对象的一部分,但是成员对象可以脱离整体对象而独立存在。
例如图书馆和学生之间的关联,图书馆被拆了,但是学生依然存在;

java语言模型训练 java建模语言_System_06


关联(Association)关系组合(Composition)关系 表示类之间的整体与 部分的关系,但它是一种更强烈的聚合关系,是 cxmtains-a 关系。在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不存在,部分对象不能脱离整体对象而存在。

例如人体的头部和身体;少了任何一方,普通人类生存是比较困难的.

java语言模型训练 java建模语言_java语言模型训练_07


泛化(Generalization)关系对象之间耦合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的关系,继承关系,是 is-a 的关系。在 UML 类图中,泛化关系用带空心三角箭头的实线来表示,箭头从子类指向父类。在代码实现时,使用面向对象的继承机制来实现泛化关系。

类继承类, 接口继承接口

java语言模型训练 java建模语言_System_08


实现(Realization)关系接口与实现类之间的关系
在 UML 类图中,实现关系使用带空心三角箭头的虚线来表示,箭头从实现类
指向接口。

java语言模型训练 java建模语言_代理模式_09


2.面向对象语言的设计原则

java语言模型训练 java建模语言_代理模式_10


重点知识学习(6.1)–[Java的23种设计模式以及设计原则笔记链接整理]

3.单例模式

单例模式

仅提供一个实例对象的模式,

例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误

  • 单例类只有一个实例对象;
  • 该单例对象必须由单例类自行创建;
  • 单例类对外提供一个访问该单例的全局访问点(提供一个公共的访问方法,内含创建对象);

通常用的有两种方式

java语言模型训练 java建模语言_java_11

懒汉式:

  • 在类加载时,不会创建单例对象, 在第一次访问时,才会去创建;
  • 懒汉式单例有线程安全问题,必须要加锁处理

案例:

/*
 * 懒汉式单例
 */
public class Singleton {
	
	//定义静态的属性;
	private static Singleton instance;  
	
	//构造方法私有化;
    private Singleton (){
    	
	}  
    
    //向外界提供获取实例的方法  加锁 synchronized 才能保证单例
    public static synchronized Singleton getInstance() {  
	    if (instance == null) {  
	        instance = new Singleton();  
	    }  
      return instance;  
    }
}

测试

public class Test {
	 public static void main(String[] args) {
		 
	      //获取唯一可用的对象
		 Singleton object1 = Singleton.getInstance();
		 Singleton object2 = Singleton.getInstance();
		 Singleton object3 = Singleton.getInstance();
		 System.out.println(object1);
		 System.out.println(object2);
		 System.out.println(object3);

		 System.out.println(object1 == object2);
	}
}

结果

com.xiaozhi.advanced.day06_moshi.singleton.demo1.Singleton@4b67cf4d
com.xiaozhi.advanced.day06_moshi.singleton.demo1.Singleton@4b67cf4d
com.xiaozhi.advanced.day06_moshi.singleton.demo1.Singleton@4b67cf4d
true

饿汉式: (急切式):
在类加载时,就会创建此单例对象,这种写法不会出现线程安全问题;

案例:

/*
 * 饿汉式单例
 */
public class Singleton {
	
	   //创建 Singleton 的一个对象
	   private static Singleton instance = new Singleton();
	 
	   //让构造函数为 private
	   private Singleton(){}
	 
	   //获取唯一可用的对象
	   public static Singleton getInstance(){
	      return instance;
	   }
}

测试:

public class Test {
	 public static void main(String[] args) {
		 
	      //获取唯一可用的对象
		 Singleton object1 = Singleton.getInstance();
		 Singleton object2 = Singleton.getInstance();
		 Singleton object3 = Singleton.getInstance();
		 System.out.println(object1);
		 System.out.println(object2);
		 System.out.println(object3);

		 System.out.println(object1 == object2);
	}
}

结果:

com.xiaozhi.advanced.day06_moshi.singleton.demo2.Singleton@4b67cf4d
com.xiaozhi.advanced.day06_moshi.singleton.demo2.Singleton@4b67cf4d
com.xiaozhi.advanced.day06_moshi.singleton.demo2.Singleton@4b67cf4d
true

4.工厂模式

工厂模式

定义一个创建产品对象的工厂接口,将产品对象的实际创建工作放置到工厂类当中。
“创建与使用相分离”

被创建的对象称为“产品”,``创建产品的对象称为“工厂”。 如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。

在简单工厂模式中创建实例的方法通常为静态(static)方法,因此简单工厂模式(Simple Factory Pattern)又叫作静态工厂方法模式(Static Factory MethodPattern)。

例如:简单工厂

简单工厂(SimpleFactory)创建所需的产品对象,工厂类的创建产品类的方法可以被外界直接调用,

抽象产品(Product):是简单工厂创建的所有对象的父类,负责描述所有实例共有的公共接口。

具体产品(ConcreteProduct):实现了抽象的接口/抽象类的具体实现类 .

java语言模型训练 java建模语言_System_12

java语言模型训练 java建模语言_System_13

案例:
抽象产品

//抽象产品
public interface Product {
    void show();
}

具体产品A

public class ProductA implements Product {
    @Override
    public void show() {
        System.out.println("具体产品A显示...");
    }
}

具体产品B

public class ProductB implements Product {

    @Override
    public void show() {
        System.out.println("具体产品B显示...");
    }
}

工厂

/*
 * 工厂:生产对象
 */
public class SimpleFactory {

	   public Product createProduct(String className){
		   if(className == null){
			   return null;
		   }else{
				try {
					//使用了反射机制;
					return (Product) Class.forName(className).newInstance();
				} catch (InstantiationException e) {
					e.printStackTrace();
					return null;
				} catch (IllegalAccessException e) {
					e.printStackTrace();
					return null;
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
					return null;
				}
		   }      
	   }
}

测试

public class Test {
	 public static void main(String[] args) {
	      SimpleFactory simpleFactory = new SimpleFactory();

		 Product productA = simpleFactory.createProduct("com.xiaozhi.advanced.day06_moshi.simplefactory.ProductA");

		 Product productB = simpleFactory.createProduct("com.xiaozhi.advanced.day06_moshi.simplefactory.ProductB");

		 productA.show();
		 productB.show();
	 }
}
具体产品A显示...
具体产品B显示...

5.代理模式

代理模式

比如说,你有好多套房子要出租;但是你觉得自己带客户看房子比较麻烦,就找了中介来作为中间件;让中介帮你把房子租出去;这就像是个简单的代理模式原理;

一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。

  • 保护目标对象
  • 对目标的功能进行扩展
  • 将用户和目标进行分类,降低了耦合度

代理模式的结构:

  • 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  • 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

java语言模型训练 java建模语言_System_14


静态代理

  • 一般使用于关系是固定的,代理某类事务必须实现接口,
  • 若代理多个目标对象,那么就需要实现更多的接口,后期维护比较麻烦.

静态代理模式的特点,代理类接受一个 Subject 接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。

缺点:每一个代理类都必须实现一遍委托类(也就是 realsubject)的接口,如果接口增加方法,则代理类中也必须跟着一起修改。(有点违反开闭原则了)
代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,效率降低.

案例

比如经常写的SSM结构下的调用;

持久层接口定义抽象方法;

/*
  Dao接口,定义保存功能的抽象方法;
 */
public interface BaseDao {
	void save();
}

具体的持久层实现类;

/*
  实际功能实现类
 */
public class UserDaoImpl implements BaseDao {
	//子类重写实现;
	@Override
	public void save() {
		System.out.println("UserDaoImpl:save()");
	}
}

静态代理类

/*
 * 静态代理类
 */
public class StaticDaoProxy implements BaseDao {

	//接收所有实现BaseDao接口的实现类对象
	private BaseDao baseDao;

	// 将被代理者的实例传进动态代理类的构造函数中
	public StaticDaoProxy(BaseDao baseDao) {
		this.baseDao = baseDao;
	}

	//代理他们实现功能,可以在调用前,调用后 写上前置/后置的方法;
	//有点AOP的感觉了;
	@Override
	public void save() {
		System.out.println("before");
		baseDao.save();
		System.out.println("after");
	}
}

测试:

public class Test {
	 public static void main(String[] args) {
	 	  //把实际执行者交给代理对象管理即可
		  StaticDaoProxy subject = new StaticDaoProxy(new UserDaoImpl());
	      subject.save();
     }
}
before
UserDaoImpl:save()
after

动态代理

代理类不在 Java 代码中实现,而是在运行时期生成

  • 相比静态代理,动态代理可方便对委托类的方法进行统一处理,如添加方法,调用次数,添加日志功能.
  • 动态代理分为 jdk 动态代理和 cglib 动态代理

JDK代理

通过反射来实现,借助 Java 自带的java.lang.reflect.Proxy,通过固定的规则生成。

  • 不需要代理类指定的去实现某些抽象接口, 代理的扩展性好.
  • 动态生成代理对象, 要求目标类必需有实现接口(以前的spring项目结构持久层都得需要结构,下置实现类).

  • 编写一个委托类的接口,即静态代理的
  • 实现一个真正的委托类,即静态代理的
  • 创建一个动态代理类,实现 InvocationHandler 接口,并重写该 invoke方法
  • 在测试类中,生成动态代理的对象。

案例;以刚才的案例为例,接口和实现类不变,代理类改变;

/*
 * 动态代理类;实现 InvocationHandler 接口,并重写该 invoke方法
 */
public class DynamicDaoProxy implements InvocationHandler {

	// 被代理类的实例
	private Object object;

	// 将被代理者的实例传进动态代理类的构造函数中
	public DynamicDaoProxy(Object object) {
		this.object = object;
	}

	/*
	 * 覆盖InvocationHandler接口中的invoke()方法
	 *    Object proxy 表示代理对象
	 *    Method method 代理对象中的方法
	 *	  Object[] args  表示代理方法中的参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("before");
		//反射机制获取,目标对象的方法;
		Object result = method.invoke(object, args);
		System.out.println("after");
		return result;
	}
}

测试

public class Test {
	 public static void main(String[] args) {
		 //代理的真实对象
		 UserDaoImpl userDaoImpl = new UserDaoImpl();
		 //代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
		 InvocationHandler dynamicProxy = new DynamicDaoProxy(userDaoImpl);
		 /*
		  * 通过Proxy的newProxyInstance方法来创建代理对象
		  * 第一个参数 handler.getClass().getClassLoader() ,使用handler这个类的ClassLoader对象来加载代理对象
		  * 第二个参数realSubject.getClass().getInterfaces(),为代理对象提供的接口是真实对象所实行的接口,表示代理的是该真实对象,即可调用这组接口中的方法
		  * 第三个参数dynamicProxy,将这个代理对象关联到了上方的 InvocationHandler 这个对象上
		  */
		 BaseDao baseDao = (BaseDao) Proxy.newProxyInstance(dynamicProxy.getClass().getClassLoader(), userDaoImpl.getClass().getInterfaces(), dynamicProxy);
		 baseDao.save();
     }
}
before
UserDaoImpl:save()
after

spring框架项目中,需要用到接口;

**spring早期框架 使用的动态代理只有Jdk代理;而Jdk代理要求目标类必须实现接口, 架构扩展方法时的需求;**


CgLib代理

对于没有接口的类,需要CgLib代理实现动态代理

采用字节码技术,原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
由于采用的是继承,所以不能对final 修饰的类进行代理
相比于Jdk代理;CgLib代理创建代理对象时所花费的时间却比 JDK 多

  • 需要引入 cglib 的 jar 文件,但是 Spring 的核心包中已经包括了 Cglib 功能,所以直接引入 spring-core-xxx.jar 即可.
  • 引入功能包后,就可以在内存中动态构建子类
  • 代理的类不能为 final,否则报错
  • 目标对象的方法如果为 final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.

案例
这里就不需要接口了;

//具体主题
public class UserDaoImpl {
	public void save() {
	 System.out.println("UserDaoImpl:save()");
	}
}

动态代理类

/*
 * 动态代理类
 */
public class CGLibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class<?> clazz) {
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    /*
     * 拦截所有目标类方法的调用
     * 参数:
     * obj  目标实例对象
     * method 目标方法的反射对象
     * args 方法的参数
     * proxy 代理类的实例
     */
    public Object intercept(Object obj, Method method, Object[] args,
                            MethodProxy proxy) throws Throwable {
        //代理类调用父类的方法
        System.out.println("开始事务");
        Object obj1 = proxy.invokeSuper(obj, args);
        System.out.println("关闭事务");
        return obj1;
    }
}

测试

public class Test {
	 public static void main(String[] args) {
		  CGLibProxy proxy = new CGLibProxy();
		  UserDaoImpl userDaoImpl = (UserDaoImpl) proxy.getProxy(UserDaoImpl.class);
		  userDaoImpl.save();
	}
}
开始事务
UserDaoImpl:save()
关闭事务