设计模式
Java 中一般认为有 23 种设计模式,我们不需要所有的都会,但是其中常用的几种设计模式应该去掌握。下面列出了所有的设计模式。需要掌握的设计模式我单独列出来了,当然能掌握的越多越好。
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式。其定义为:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式实现方式:
/**
* @ fileName:eSingleton
* @ description: 饿汉式单例模式
* @ author:wxh
* @ createTime:2022/6/17 19:01
* @ version:1.0.0
*/
public class ESingleton {
public static ESingleton eSingleton = new ESingleton();
public ESingleton() {
}
public static ESingleton getSingleton(){
return eSingleton;
}
}
/**
* @ fileName:LSingleton
* @ description: 懒汉式
* @ author:wxh
* @ createTime:2022/6/17 19:06
* @ version:1.0.0
*/
public class LSingleton {
private static LSingleton lSingleton;
public LSingleton() {
}
//双重校验锁
public static LSingleton getlSingleton(){
if(lSingleton != null){
synchronized (LSingleton.class){
lSingleton = new LSingleton();
}
}
return lSingleton;
}
}
public static void main(String[] args){
//创建单例模式 饿汉式
ESingleton eSingleton = ESingleton.getSingleton();
ESingleton eSingleton2 = ESingleton.getSingleton();
System.out.println(eSingleton == eSingleton2);
//懒汉式
System.out.println(LSingleton.getlSingleton() == LSingleton.getlSingleton());
}
代理模式
静态代理
静态代理:由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口、被代理类、代理类等确定下来。在程序运行之前,代理类的.class文件就已经生成。
public interface ITeacherDao {
void teach(); // 授课的方法
}
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
//对象实现类
System.out.println(" 老师授课中 。。。。。");
}
}
/**
* @description: 通过构造将被代理类传进来 调用方法
*
* @return {@link null}
* @author wangxihao
* @email wangxh0108@163.com
**/
public class TeacherDaoProxy implements ITeacherDao{
private ITeacherDao target; // 目标对象,通过接口来聚合
//构造器
public TeacherDaoProxy(ITeacherDao target) {
this.target = target;
}
@Override
public void teach() {
// TODO Auto-generated method stub
System.out.println("开始代理 完成某些操作。。。。。 ");//方法
target.teach();
System.out.println("提交。。。。。");//方法
}
}
public static void main(String[] args) {
//创建目标对象(被代理对象)
TeacherDao teacherDao = new TeacherDao();
//创建代理对象, 同时将被代理对象传递给代理对象
TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
//通过代理对象,调用到被代理对象的方法
//即:执行的是代理对象的方法,代理对象再去调用目标对象的方法
teacherDaoProxy.teach();
}
JDK 动态接口代理
JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler。
InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类
的代码,动态将横切逻辑和业务逻辑编制在一起。Proxy 利用 InvocationHandler 动态创建
一个符合某一接口的实例,生成目标类的代理对象。
public interface ITeacherDao {
void teach(); // 授课方法
}
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println(" 老师授课中.... ");
}
}
public class ProxyFactory {
//维护一个目标对象 , Object
private Object target;
//构造器 对target 进行初始化 将代理对象传进来
public ProxyFactory(Object target) {
this.target = target;
}
//给目标对象 生成一个代理对象
public Object getProxyInstance() {
//说明
/*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
//1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
//2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
//3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
//目标对象实现的接口类型 反射获取加载器 目标对象实现的接口类型
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理开始~~");
//反射机制调用目标对象的方法
Object returnVal = method.invoke(target, args);
System.out.println("JDK代理提交");
return returnVal;
}
});
}
}
public static void main(String[] args) {
//创建目标对象
ITeacherDao target = new TeacherDao();
//给目标对象,创建代理对象, 可以转成 ITeacherDao
ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
// proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
System.out.println("proxyInstance=" + proxyInstance.getClass());
//通过代理对象,调用目标对象的方法
proxyInstance.teach();
}
CGlib动态代理
CGLib 全称为 Code Generation Library,是一个强大的高性能,高质量的代码生成类库,
可以在运行期扩展 Java 类与实现 Java 接口,CGLib 封装了 asm,可以再运行期动态生成新
的 class。和 JDK 动态代理相比较:JDK 创建代理有一个限制,就是只能为接口创建代理实例,
而对于没有通过接口定义业务方法的类,则可以通过 CGLib 创建动态代理。
public class TeacherDao {
public String teach() {
System.out.println(" 老师授课中 , 我是cglib代理,不需要实现接口 ");
return "hello";
}
}
public class ProxyFactory implements MethodInterceptor {
/**
* <!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
* <dependency>
* <groupId>org.ow2.asm</groupId>
* <artifactId>asm</artifactId>
* <version>7.1</version>
* </dependency>
* <!-- https://mvnrepository.com/artifact/org.ow2.asm/asm-commons -->
* <dependency>
* <groupId>org.ow2.asm</groupId>
* <artifactId>asm-commons</artifactId>
* <version>7.1</version>
* </dependency>
* <!-- https://mvnrepository.com/artifact/org.ow2.asm/asm-tree -->
* <dependency>
* <groupId>org.ow2.asm</groupId>
* <artifactId>asm-tree</artifactId>
* <version>7.1</version>
* </dependency>
* <!-- https://mvnrepository.com/artifact/cglib/cglib -->
* <dependency>
* <groupId>cglib</groupId>
* <artifactId>cglib</artifactId>
* <version>3.3.0</version>
* </dependency>
*/
//维护一个目标对象
private Object target;
//构造器,传入一个被代理的对象
public ProxyFactory(Object target) {
this.target = target;
}
//返回一个代理对象: 是 target 对象的代理对象
public Object getProxyInstance() {
//1. 创建一个工具类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创建子类对象,即代理对象
return enhancer.create();
}
//重写 intercept 方法,会调用目标对象的方法
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("Cglib代理模式 ~~ 开始");
Object returnVal = method.invoke(target, args);
System.out.println("Cglib代理模式 ~~ 提交");
return returnVal;
}
}
public static void main(String[] args) {
//创建目标对象
TeacherDao target = new TeacherDao();
//获取到代理对象,并且将目标对象传递给代理对象
TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();
//执行代理对象的方法,触发intecept 方法,从而实现 对目标对象的调用
String res = proxyInstance.teach();
System.out.println("res=" + res);
}
工厂设计模式
工厂模式分为工厂方法模式和抽象工厂模式。
工厂方法模式
工厂方法模式分为三种:
普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
普通工厂模式:
public interface User {
public void createUser();
}
public class Usera implements User {
@Override
public void createUser() {
System.out.println("创建了Usera!");
}
}
public class Userb implements User {
@Override
public void createUser() {
System.out.println("创建了Userb!");
}
}
public class UserFactory {
public User produce(String type){
if(type.contains("a")){
return new Usera();
}else{
return new Userb();
}
}
}
public static void main(String[] args){
//普通工厂
UserFactory userFactory = new UserFactory();
User a = userFactory.produce("a");
a.createUser();
}
多工厂方法模式
该模式是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
public interface User {
public void createUser();
}
public class Usera implements User {
@Override
public void createUser() {
System.out.println("创建了Usera!");
}
}
public class Userb implements User {
@Override
public void createUser() {
System.out.println("创建了Userb!");
}
}
public class UserFactory {
public User createUsera(){
return new Usera();
}
public User createUserb(){
return new Userb();
}
}
public static void main(String[] args){
//普通多工厂
UserFactory userFactory = new UserFactory();
User usera = userFactory.createUsera();
User userb = userFactory.createUserb();
usera.createUser();
userb.createUser();
}
抽象工厂模式
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
public interface User {
public void createUser();
}
public class Usera implements User {
@Override
public void createUser() {
System.out.println("创建了Usera!");
}
}
public class Userb implements User {
@Override
public void createUser() {
System.out.println("创建了Userb!");
}
}
public interface Provider {
public User CreateUserFactory();
}
public class UseraFactory implements Provider {
@Override
public User CreateUserFactory() {
return new Usera();
}
}
public class UserbFactory implements Provider {
@Override
public User CreateUserFactory() {
return new Userb();
}
}
public static void main(String[] args){
//总体工厂创建接口 创建工厂并创建对象
Provider factory = new UseraFactory();
User a = factory.CreateUserFactory();
a.createUser();
}
适配器设计模式
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。
类的适配器模式
public interface IDept {
public void createDept();
public void createDeptb();
}
public class Dept {
public void createDept(){
System.out.println("创建dept");
}
}
public class Adapter extends Dept implements IDept {
@Override
public void createDeptb() {
System.out.println("创建b");
}
}
//某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题
public static void main(String[] args){
Adapter adapter = new Adapter();
adapter.createDept();
adapter.createDeptb();
}
对象的适配器模式
基本思路和类的适配器模式相同,只是将 Adapter 类作修改,这次不继承 Source 类,而是持有 Source 类的实例,以达到解决兼容性的问题。
接口的适配器模式
接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。
装饰模式(Decorator)
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。
public interface User {
public void method();
}
public class Usera implements User {
@Override
public void method() {
System.out.println("usera!");
}
}
public class Userb implements User {
@Override
public void method() {
System.out.println("userb!");
}
}
/**
* @ fileName:DecoratorClass
* @ description: 装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例
* @ author:wxh
* @ createTime:2022/6/17 20:22
* @ version:1.0.0
*/
public class DecoratorClass implements User {
private User user;
public DecoratorClass(User user) {
this.user = user;
}
public DecoratorClass() {
}
@Override
public void method() {
System.out.println("之前新增装饰");
user.method();
System.out.println("之后新增装饰");
}
public static void main(String[] args){
Usera usera = new Usera();
DecoratorClass decoratorClass = new DecoratorClass(usera);
decoratorClass.method();
}
}
观察者模式(Observer)
观察者模式很好理解,类似于邮件订阅和 RSS 订阅,当我们浏览一些博客或 wiki 时,经常会看到 RSS 图标,就这的意思是,当你订阅了该文章,如果后续有更新,会及时通知你。其实,简单来讲就一句话:当一个对象变化时,其它依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。
public interface Observer {
//定义观察者
public void update();
}
class Observera implements Observer{
//定义观察者 添加观察后执行的事件
@Override
public void update() {
System.out.println("observea观察到改动执行");
}
}
class Observerb implements Observer{
//定义观察者 添加观察后执行的事件
@Override
public void update() {
System.out.println("observeb观察到改动执行");
}
}
/**
* @ fileName:subject
* @ description: 操作观察者
* @ author:wxh
* @ createTime:2022/6/17 20:30
* @ version:1.0.0
*/
public interface subject {
//操作观察者的事件
public void add(Observer observer);
public void delete(Observer observer);
//通知所有观察者
public void notifyObserver();
//被观察者自身操作
public void operation();
}
//抽象类 等待业务类继承调用
public abstract class AbstractObserver implements subject {
private Vector<Observer> vector = new Vector<>();
//观察者的事件
@Override
public void add(Observer observer) {
vector.add(observer);
}
@Override
public void delete(Observer observer) {
vector.remove(observer);
}
@Override
public void notifyObserver() {
Enumeration<Observer> elements = vector.elements();
while (elements.hasMoreElements()){
elements.nextElement().update();
}
}
//被观察者自己的操作
@Override
public void operation() {
}
}
/**
* @ fileName:MySubject
* @ description: 被观察者 业务类
* @ author:wxh
* @ createTime:2022/6/17 20:41
* @ version:1.0.0
*/
public class MySubject extends AbstractObserver {
@Override
public void operation() {
System.out.println("执行自己的业务!");
notifyObserver(); //唤醒观察
}
}
public static void main(String[] args){
MySubject mySubject = new MySubject();
mySubject.add(new Observera()); //添加观察者a的事件
mySubject.add(new Observerb());//添加观察者b的事件
mySubject.operation();
}
建造者模式(Builder)
工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的 Test 结合起来得到的
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/75438.html