编程技术是改变世界的力量。
本站
当前位置:网站首页 > 后端语言 > 正文

java设计模式 java设计模式七大原则

gowuye 2024-04-03 16:15 24 浏览 0 评论

设计模式类别:

java的设计模式大体上分为三大类:

  1. 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。一种对象创建型模式,它可以将复杂对象的建造过程抽象出来(抽象类别)抽象类、接口,使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
    建造者模式意在为重叠构造器这种反模式(telescoping constructor anti-pattern)找到一种解决方案
  2. 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式(队列、栈),桥接模式,组合模式,享元模式。这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
  3. 行为型模式(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性能高。

相关推荐

爱上开源之golang入门至实战第四章-切片(Slice)

前言Go数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可...

Go语言入门必知教程-切片

切片是一种灵活的和可扩展的数据结构,用于实现和管理数据集。切片由多个元素组成,所有元素都是相同类型的。切片是动态数组的一部分,可以根据需要进行增长和收缩。与数组一样,切片也可以索引。切片具有容量和长度...

Go语言基础-切片

切片是什么?切片是Go语言的一种数据结构。和数组相似,不过切片可以在它的结尾增加更多的元素。这样可变长度在实际编程中更为有用。声明切片切片的声明和数组也很相似,只是声明切片时不需要指定大小。例:va...

5分钟掌握GO中切片的基本使用方法

最近Golang越来越火,不少小伙伴都纷纷开始学习Golang,但对于原先为C++或者JAVA的同学,用习惯了数据、list、vector等,会对Go的切片slice不习惯,下面整理出go中slice...

揭秘 Go 切片(Slice)的秘密

当向切片添加新参数时,底层数组会发生什么变化?它会扩展以容纳更多元素吗?在这篇文章中,我们将深入探讨切片的内部工作原理,以及如何利用这些知识来进行更好的内存管理和性能优化。具体而言,我们将探索Go...

【Go语言slice详解】深入掌握Go语言中的slice类型及常用操作!

Go语言中的slice(切片)是一种非常方便的数据结构,可以动态地增加或减少其元素数量,且可以访问底层数组的任意一个子序列。本文将对Go语言中的slice进行详细的讲解。Slice的定义在Go语言中,...

掌握GO中的Slice,这就够了

最近Golang越来越火,不少小伙伴都纷纷开始学习Golang,但对于原先为C++或者JAVA的同学,用习惯了数据、list、vector等,会对Go的切片slice不习惯,下面整理出go中slice...

golang2021面向对象(26)Go语言类型内嵌和结构体内嵌

结构体可以包含一个或多个匿名(或内嵌)字段,即这些字段没有显式的名字,只有字段的类型是必须的,此时类型也就是字段的名字。匿名字段本身可以是一个结构体类型,即结构体可以包含内嵌结构体。?可以粗略地将这个...

2022-11-13:以下go语言代码中,如何获取结构体列表以及结构体内

2022-11-13:以下go语言代码中,如何获取结构体列表以及结构体内的指针方法列表?以下代码应该返回{"S1":["M1","M2"],"S...

Go语言文件和目录操作

文件和目录操作概述一、文件和目录操作概述在计算机中,文件和目录是存储数据的重要方式。在Go语言中,我们可以使用os和io/ioutil包提供的函数和结构体来进行文件和目录操作。本文将详细介绍Go语言中...

跟我一起学习go语言(五)golang中结构体的初始化方法

1、自定义一个结构体typeVertexstruct{X,Yfloat64}2、初始化方法-指针:rect1:=new(Vertex)rect2:=&Vertex...

Go复合数据类型:结构体

一种通用的、对实体对象进行聚合抽象的能力,在Go中,提供这种聚合抽象能力的类型是结构体类型,也就是struct。自定义一个新类型在Go中,我们自定义一个新类型一般有两种方法。第一种是类型定义...

Go语言基础:方法

导读在阅读本文章前,假定你具备如下能力:?已掌握结构体1.方法1.1方法的概念在理解程序中方法的概念时,我们先看看现实中的一些情况,这样相对比较好理解一些。在农村的朋友可能会知道,在医疗落后的情况...

为什么 Go 语言 struct 要使用 tags

在Go语言中,struct是一种常见的数据类型,它可以用来表示复杂的数据结构。在struct中,我们可以定义多个字段,每个字段可以有不同的类型和名称。除了这些基本信息之外,Go还提供了s...

一文带你掌握掌握 Golang结构体与方法

1.Golang结构体的概念及定义结构体是Golang中一种复合类型,它是由一组具有相同或不同类型的数据字段组成的数据结构。结构体是一种用户自定义类型,它可以被用来封装多个字段,从而实现数据的...

取消回复欢迎 发表评论: