设计模式
单例模式
简单点说,就是一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()方法来获取它们的实例;
1.构造方法私有化;2.实例化的变量引用私有化;3.获取实例的方法公有
getInstance()的返回值是一个对象的引用,并不是一个新的实例,所以不要错误的理解成多个对象。
单例模式的实现:
public class Singleton {private static Singleton singleton;private Singleton() {}public static Singleton getInstance(){if(singleton == null){singleton = new Singleton();}return singleton;}}
这是最基本的写法,也叫懒汉式写法(线程不安全),下面再介绍几种单例模式的实现方法:
懒汉式写法(线程安全)
public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}
饿汉式写法
public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}}
静态内部类
public class Singleton {private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}private Singleton() {}public static final Singleton getInstance() {return SingletonHolder.INSTANCE;}}
枚举
public enum Singleton {INSTANCE;public Singleton getInstance(){return INSTANCE;}}
这种方式是《Effective Java》作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,
单元素的枚举类型已经成为实现Singleton的最佳方法。
双重校验锁
public class Singleton {private volatile static Singleton singleton;private Singleton() {}public static Singleton getInstance() {if(singleton == null) {synchronized(Singleton.class) {if(singleton == null) {singleton == new Singleton();}}}return singleton;}}
观察者模式
在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。
其实就是发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息。

- 抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
- 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
- 具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
小结:
- 这个模式是松偶合的。改变主题或观察者中的一方,另一方不会受到影像。
- JDK中也有自带的观察者模式。但是被观察者是一个类而不是接口,限制了它的复用能力。
- 在JavaBean和Swing中也可以看到观察者模式的影子。
装饰者模式
介绍:对已有的业务逻辑进一步的封装,使其增加额外的功能,Java中的IO流就是用了装饰者模式,用户在使用的时候,可以任意组装,达到自己想要的效果。
装饰者模式由四部分组成
- 抽象组件:需要装饰的抽象对象,(接口或抽象类)
- 具体组件:实现抽象组件,需要装饰的对象;
- 抽象装饰类:实现抽象组件,包含了对抽象组件的引用,并声明装饰方法;
- 具体装饰类:继承抽象装饰类,实现抽象方法,可以有多个;
示例:
/*** 装饰器设计模式:咖啡模拟,修饰器 牛奶、糖、* 1、抽象组件:需要装饰的抽象对象(接口或抽象父类) 饮品* 2、具体组件:需要装饰的对象 咖啡* 3、抽象装饰类:包含了对抽象组件的引用以及装饰着共有的方法* 4、具体装饰类:被装饰的对象 糖、牛奶* @author Tassel*/public class DecorateTest {public static void main(String[] args) {Drink coffee = new Coffee(); //原味咖啡System.out.println(coffee.info() + coffee.price());Drink milkCoffee = new Milk(coffee); // 加牛奶System.out.println(milkCoffee.info() + milkCoffee.price());Drink sugerCoffee = new Suger(coffee); // 加糖System.out.println(sugerCoffee.info() + sugerCoffee.price());}}// 1.抽象组件:饮品interface Drink {double price(); //价格String info(); //说明}//2.具体组件: 咖啡class Coffee implements Drink {private String name = "原味咖啡";@Overridepublic double price() {return 10;}@Overridepublic String info() {return name;}}//3. 抽象装饰类abstract class DrinkDecorate implements Drink {//对抽象组件的引用private Drink drink;public DrinkDecorate (Drink drink) {this.drink = drink;}@Overridepublic double price() {return this.drink.price();}@Overridepublic String info() {return this.drink.info();}}//4.1 具体装饰类 : 牛奶class Milk extends DrinkDecorate {public Milk(Drink drink) {super(drink);}@Overridepublic double price() {return super.price()*4;}@Overridepublic String info() {return super.info() + "加入了牛奶装饰";}}//4.2 具体装饰类 : 糖class Suger extends DrinkDecorate {public Suger(Drink drink) {super(drink);}@Overridepublic double price() {return super.price()*2;}@Overridepublic String info() {return super.info() + "加入了糖装饰";}}
适配器模式
将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
角色:
Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类;
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类时适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系;
Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。
示例:类适配器
//适配者类public class Adaptee {public void adapteeRequest() {System.out.println("被适配者的方法");}}
//目标接口public interface Target {void request();}
public class Adapter extends Adaptee implements Target{@Overridepublic void request() {// 其他操作...super.adapteeRequest();// 其他操作...}}
示例:对象适配器
对象适配器与类适配器不同之处在于,类适配器通过继承来完成适配,对象适配器则是通过关联来完成,这里稍微修改一下 Adapter 类即可将转变为对象适配器。
public class Adapter implements Target{// 适配者是对象适配器的一个属性private Adaptee adaptee = new Adaptee();@Overridepublic void request() {// 其他操作...adaptee.adapteeRequest();// 其他操作...}}
静态代理模式
- RealSubject:真实对象,是实现抽象接口的类。
- Proxy:代理对象,内部含有对真实对象
RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。- 静态代理:有一个类文件描述代理模式
- 动态代理:在内存中形成代理类
- Subject : 接口,是对象和它的代理共用的接口,让
RealSubject和Proxy具有一致性。
实现步骤:
- 代理对象和真实对象实现相同的接口;
- 代理对象 = Proxy.newProxyInstance(三个参数);[动态代理]
参数:- 类加载器:真实对象.getClass().getClassLoader()
- 接口数组:真实对象.getClass().getInterfaces()
- 处理器:new InvocationHndler()
- 使用代理对象调用方法;
- 增强方法;
package com.tassel.thread;/*** 实现静态代理 公共接口: 1.真实角色(对象) 2.代理角色(对象)**/public class StaticProxy {public static void main(String[] args) {new WeddingCompany(new You()).happyMarry();// 类似多进程的// new Thread(线程对象).start();}}// 公共接口 结婚interface Marry {void happyMarry();}// 真实角色 你结婚class You implements Marry {@Overridepublic void happyMarry() {System.out.println("真实角色:我要结婚");}}// 代理角色 婚庆公司class WeddingCompany implements Marry {private Marry target;public WeddingCompany(Marry target) {this.target = target;}@Overridepublic void happyMarry() {System.out.println("代理角色:有人要结婚接个活");target.happyMarry();System.out.println("代理角色:人家结完婚了,咱该走了");}}
动态代理模式
- 特点:字节码随用随创建,随用随加载;
- 作用:不修改方法代码的基础上对方法增强
- 分类:
- 基于接口的动态代理
- 基于子类的动态代理
https://www.cnblogs.com/tuyang1129/p/12878549.html
基于接口的动态代理
- 涉及的类:JDK官方提供的Proxy
- 如何创建代理对象:使用Proxy类中的newProxyInstance方法
- 创建代理对象的要求:被代理类最少实现一个接口,如果没有则不能使用
- newProxyInstance方法的参数:
- ClassLoader:类加载器,用于加载代理对象字节码的,即被代理对象的类加载器
- Class[]:字节码数组,用于让代理对象和被代理对象有相同的方法。即被代理对象的接口
- InvocationHandler:它是让我们写如何代理,一般都是写一个该接口的实现类,一般情况下是匿名内部类,非必然,此接口的实现类,谁用谁写。 ```java // 被代理对象 final Producer producer = new Producer();
IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler(){ /**
* 作用:执行被代理对象的任何借口方法都会执行该方法;* @param proxy:代理对象的引用* @param method:当前执行的方法* @param args:当前执行方法所需的参数* @return:与被代理对象方法有相同的返回值* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 提供增强的代码Object returnValue = null;// 获取方法执行的参数Float money = (Float) args[0];// 判断当前方法是不是销售if ("saleProduct".equals(method.getName())) {returnValue = method.invoke(producer, money * 0.8f);}return returnValue;}
});
<a name="4de5d68b"></a>### 基于子类的动态代理- **涉及的类**:第三方cglib库,需要导jar包- **如何创建代理对象**:使用Enhancer类中的create方法- **创建代理对象的要求**:被代理类不能是最终类- create方法的参数:- Class:字节码,用于指定被代理对象的字节码- Callback:用于提供增强的代码,它是让我们写如何代理。一般来实现该接口的子接口:MethodInterceptor```javaProducer cglibProducer = (Producer) Enhancer.create(producer.getClass(), new MethodInterceptor() {/*** 执行代理对象的任何方法都会执行该方法* @param proxy:代理对象的引用* @param method:当前执行的方法* @param args:当前执行方法所需的参数* @param* @return*/@Overridepublic Object intercept(Object proxy, Method method, Object[] orgs, MethodProxy methodProxy) throws Throwable {// 提供增强的代码Object returnValue = null;// 获取方法执行的参数Float money = (Float) args[0];// 判断当前方法是不是销售if ("saleProduct".equals(method.getName())) {returnValue = method.invoke(producer, money * 0.8f);}return returnValue;}});
工厂模式
简单工厂模式:一个抽象的接口,多个抽象接口的实现类,一个工厂类,用来实例化抽象的接口
package com.tassel.designmodel;public class TestFactory {public static void main(String[] args) {Car car = Factory.getCarInstance("Benz");if (car != null) {car.run();car.stop();} else {System.out.println("不存在此品牌车辆!");}}}abstract interface Car {public void run();public void stop();}// 具体实现类class Benz implements Car {public void run() {System.out.println("Benz开始启动了。。。。。");}public void stop() {System.out.println("Benz停车了。。。。。");}}class Ford implements Car {public void run() {System.out.println("Ford开始启动了。。。");}public void stop() {System.out.println("Ford停车了。。。。");}}// 工厂类class Factory {public static Car getCarInstance(String type) {Car car = null;if ("Benz".equals(type)) {car = new Benz();}if ("Ford".equals(type)) {car = new Ford();}return car;}}
工厂方法模式:有四个角色,抽象工厂模式,具体工厂模式,抽象产品模式,具体产品模式。不再是由一个工厂类去实例化具体的产品,而是由抽象工厂的子类去实例化产品;
// 抽象产品角色public interface Moveable {void run();}// 具体产品角色public class Plane implements Moveable {@Overridepublic void run() {System.out.println("plane....");}}public class Broom implements Moveable {@Overridepublic void run() {System.out.println("broom.....");}}// 抽象工厂public abstract class VehicleFactory {abstract Moveable create();}// 具体工厂public class PlaneFactory extends VehicleFactory {public Moveable create() {return new Plane();}}public class BroomFactory extends VehicleFactory {public Moveable create() {return new Broom();}}// 测试类public class Test {public static void main(String[] args) {VehicleFactory factory = new BroomFactory();Moveable m = factory.create();m.run();}}
抽象工厂模式:与工厂方法模式不同的是,工厂方法模式中的工厂只生产单一的产品,而抽象工厂模式中的工厂生产多个产品
// 抽象工厂类public abstract class AbstractFactory {public abstract Vehicle createVehicle();public abstract Weapon createWeapon();public abstract Food createFood();}// 具体工厂类,其中Food,Vehicle,Weapon是抽象类,public class DefaultFactory extends AbstractFactory {@Overridepublic Food createFood() {return new Apple();}@Overridepublic Vehicle createVehicle() {return new Car();}@Overridepublic Weapon createWeapon() {return new AK47();}}// 测试类public class Test {public static void main(String[] args) {AbstractFactory f = new DefaultFactory();Vehicle v = f.createVehicle();v.run();Weapon w = f.createWeapon();w.shoot();Food a = f.createFood();a.printName();}}
简单工厂和抽象工厂的区别
简单工厂模式:
这个模式本身很简单而且使用在业务较简单的情况下。一般用于小项目或者具体产品很少扩展的情况(这样工厂类才不用经常更改)。
它由三种角色组成:
- 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,根据逻辑不同,产生具体的工厂产品。如例子中的Driver类。
- 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。由接口或者抽象类来实现。如例中的Car接口。
- 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现,如例子中的Benz、Bmw类。
来用类图来清晰的表示下的它们之间的关系:

抽象工厂模式:
先来认识下什么是产品族: 位于不同产品等级结构中,功能相关联的产品组成的家族。

图中的ProductA和ProductB就是两个产品树(产品层次结构);而如图所示的ProductA1和ProductB1就是一个产品族。他们都可以放到Factory1中,因此功能有所关联。同理PorductA2和ProductB2也是一个产品族。
可以这么说,它和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。
而且使用抽象工厂模式还要满足一下条件:
- 系统中有多个产品族,而系统一次只可能消费其中一族产品
- 同属于同一个产品族的产品以其使用。
来看看抽象工厂模式的各个角色(和工厂方法的如出一辙):
角色:
- 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
- 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。
- 抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
- 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
