单例设计模式(常见)
- 应用场景
- 概念
- 是应用最广的模式之一,也是最简单的设计模式
- 确保某一个类在整个系统中只有一个实例
- 优点:节省内存空间,使内存中某个对象只由本身实例一次,对外提供一个获取该类对象的方法
- 饿汉式
由于只存在对同一变量的读操作,不会导致线程安全问题。
public class Singleton {
private Singleton() {
}
private static final Singleton singleton = new Singleton();
public static Singleton getSingleton() {
return singleton;
}
}
- 懒汉式
实现线程安全主要有三步:在正确的位置加锁,双重 if 判定,volatile
public class Singleton {
private Singleton() {
}
private static Singleton singleton;
public static synchronized Singleton getSingleton() {
if (singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
- 双重校验锁
- volatile关键字
- Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。
- 具备两种特性:1.保证此变量对所有的线程的可见性,2.禁止指令重排序优化
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
class Resource{
public enum SomeThing {
INSTANCE;
private Resource instance;
SomeThing() {
instance = new Resource();
}
public Resource getInstance() {
return instance;
}
}
}
工厂设计模式(常见)
- 应用场景
- 在任何需要生成复杂对象的地方,都可以使用工厂方法模式。复杂对象适合使用工厂模式,用new就可以完成创建的对象无需使用工厂模式
- 概念
- 创建一个用于创建对象的接口,让子类决定实例化哪个类
public abstract class Product {
public abstract void method();
}
public class ConcreteProductA extends Product {
@Override
public void method() {
Log.e("aaaa","这是具体的产品A");
}
}
public class ConcreteProductB extends Product {
@Override
public void method() {
Log.e("aaaa","这是具体的产品B");
}
}
public abstract class Factory {
public abstract Product createProduct();
}
public class ConcreteFactory extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
代理设计模式(常见)
- 应用场景
- 概念
- 其他对象提供一个代理以控制对这个对象的访问
- 组成:被代理的具体类,代理类,执行过程
public interface Performance {
public void perform();
}
public class Show implements Performance {
@Override
public void perform() {
System.out.println("唱歌");
}
}
public class RealProxy implements Performance {
private Performance p;
public RealProxy(Performance p) {
this.p = p;
}
@Override
public void perform() {
p.perform();
}
}
- 静态代理的例子中,代理类(Proxy)是自己定义好的,在程序运行之前就已经编译完成。然而动态代理,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法
- 动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样对每一个方法或方法组合进行处理,Proxy 很美很强大,但是仅支持 interface 代理。Java 的单继承机制注定了这些动态代理类们无法实现对 class 的动态代理。好在有cglib为Proxy提供了弥补。class与interface的区别本来就模糊,在java8中更是对interface进行了加强,使得interface越来越接近class,假如哪天java突破了单继承的限制,动态代理将会更加强大
- 步骤
- 定义一个事件管理器类实现invocationHandle接口,并重写invoke(代理类,被代理的方法,方法的参数列表)方法
- 实现被代理类及其实现的接口
- 调用Proxy.newProxyInstance(类加载器,类实现的接口,事务处理器对象),生成一个代理实例
- 通过该代理实例调用方法
public interface Performance {
public void perform();
}
public class Show implements Performance {
@Override
public void perform() {
System.out.println("唱歌");
}
}
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(object, args);
return result;
}
}
public class Test {
public static void main(String[] args) {
Show show = new Show();
DynamicProxy dynamicProxy = new DynamicProxy(show);
ClassLoader loader = show.getClass().getClassLoader();
Performance p = (Performance)Proxy.newProxyInstance(loader, show.getClass().getInterfaces(), dynamicProxy);
p.perform();
}
}
public class Show{
public void perform() {
System.out.println("唱歌");
}
}
public class CGLibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class<?> clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
proxy.invokeSuper(obj, args);
return null;
}
}
public class Test {
public static void main(String[] args) {
CGLibProxy proxy = new CGLibProxy();
Show s = (Show) proxy.getProxy(Show.class);
s.perform();
}
}
装饰者模式(常见,装饰器模式)
- 应用场景
- 概念
- 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更加灵活
- 装饰者(Decorator)和具体组件(ConcreteComponent)都继承自抽象组件(Component)
- 具体组件(ConcreteComponent)是Component类的基本实现,也是我们装饰的具体对象
- 抽象装饰者(Decorator)装饰组件对象,其内部一定要有一个指向组件对象的引用
public abstract class Component {
public abstract void operate();
}
public class ConcreteComponent extends Component {
@Override
public void operate() {
}
}
public abstract class Decorator extends Component {
private Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operate() {
component.operate();
}
}
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
@Override
public void operate() {
operateA();
super.operate();
}
public void operateA() {
}
}
建造者模式(生成器模式)
- 应用场景
- 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示意图时
- 概念
- 只需指定需要创造的类型既可以得到他们,而具体建造的过程和细节就不需要知道了
原型模式
- 应用场景
- 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗
- 通过new产生的一个对象需要非常繁琐的数据准备或者权限
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝
- 概念
- 用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象
适配器模式
- 应用场景
- 系统的数据和行为都正确,但接口不相符时
- 已经存在的类的接口不符合我们的需求
- 创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作
- 在不对每一个都进行子类化以匹配它们的接口的情况下,使用一些已经存在的子类
- 概念
- 将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间
观察者模式
- 应用场景
- 某个实例的变化将影响其他多个对象。观察者模式多用于实现订阅功能,例如我们订阅了某个人的微博账号,当这个人发布了新的消息,就会通知我们
- 概念
- 定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者
- 主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的
- 依赖者(Observer)的注册功能需要调用主题的registerObserver()方法