常见设计模式

设计模式

单例设计模式

概述:一个类只有一个实例,无法 new 出一个新实例(构造器被 private 修饰),一般通过 getInstance 方法获取这个实例。
实现方式有以下五种:

  1. 饿汉式
  2. 懒汉式
  3. 静态内部类
  4. 枚举
  5. 双重校验(也属于懒汉式的一种)

饿汉式

/**
*	二话不说,直接 new 一个实例;
*	私有化构造函数;
*	实现一个 getInstance 方法返回实例;
*/
public class Singleton {  
   private static Singleton instance = new Singleton();  
   private Singleton (){}  
   public static Singleton getInstance() {  
   return instance;  
   }  
}

懒汉式

/**
*	私有化构造函数;
*	实现 getInstance 方法,该方法被 synchronized 修饰(保证线程安全)。
*/
public class Singleton {  
   private static Singleton instance;  
   private Singleton (){}  
   public static synchronized Singleton getInstance() {  
   if (instance == null) {  
       instance = new Singleton();  
   }  
   return instance;  
   }  
}

静态内部类

/**
*	私有化构造函数;
*	创建一个静态内部类,内部类里定义一个被 static 和 final 修饰的该类的实例对象;
*	实现 getInstance 方法返回静态内部类中的实例对象。
*/
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 void whateverMethod() {  
   }  
}

双重校验

/**
*	私有化构造函数;
*	定义一个被 static 和 volatile 修饰的对象;
*	实现 getInstance 方法,在调用该方法时,先判断对象为 null,
*	不为 null 则锁住当前类对象,再次判断对象是否为 null(避免在获取锁之前已被其他线程创建而重复创建),
*	为 null 则创建对象并返回。
*	使用 volatile 修饰对象是为了使所有线程对该对象有可见性,并且使指令不可重排,
*	不加 volatile 可能会造成对象还没完成初始化时被其他线程调用,获取到未完全初始化的数据。
*	new 对象分三步:
*		1. jvm 分配一个内存空间
*		2. 给对象赋默认值,对象类型为null
*		3. 再将对象指向内存,初始化完成。
*/
public class Singleton {  
	// volatile 修饰是为了避免指令重排
   	private volatile static Singleton singleton;  
   	private Singleton (){}  
   	public static Singleton getSingleton() {  
	   	if (singleton == null) {  
	       synchronized (Singleton.class) {  
	       if (singleton == null) {  
	           singleton = new Singleton();  
	       }  
	       }  
	   	}  
	   	return singleton;  
   	}  
}

总结:一般情况下饿汉式或静态内部类的实现方式比较常见,也足以应付大多数情况;
双重校验的方法面试时问得会比较多,需要深入理解。

观察者模式

概述:观察者模式一般由三个元素构成:事件源(一),事件,观察者(多),对象间有一对多的依赖关系下,当一个事件源发生事件,观察者会随之发生变化,这种模式称之为观察者模式!
举例
事件源:孩子
事件:哭
观察者:父母
当孩子哭的时候,会通知父母来安抚,喂奶等一系列操作!孩子维护着一个观察者集合(父母),当发生哭这个方法的时候遍历观察者集合执行喂奶方法!

下面是代码示例:

/**
 * 事件源:孩子
 * 事件:哭
 * 观察者集合:父母类 list
 *
 *  当孩子哭时,调用父母的喂奶方法!
 *
 */
public class Children {
    List<Parent> parents = new ArrayList<>();

    void addParent(Parent parent) {
        this.parents.add(parent);
    }

    /**
     * 孩子哭:当孩子哭时调用监护他的父母的喂奶方法!
     */
    public void cry() {
        parents.forEach(Parent::feedMilk);
    }

}


/**
 * 父母接口
 */
public interface Parent {
    /**
     * 喂奶方法
     */
    void feedMilk();
}
/**
 * 观察者:妈妈类
 */
public class Mother implements Parent {
    @Override
    public void feedMilk() {
        System.out.println("妈妈来喂奶啦!");
    }
}

/**
 * 观察者:爸爸类
 */
public class Father implements Parent {
    @Override
    public void feedMilk() {
        System.out.println("爸爸来喂奶啦!");
    }
}


装饰器模式

概述:向一个现有的类添加新功能,同时不改变其结构。
角色
被装饰者
装饰者

举例:奶茶加料
被装饰者:奶茶
装饰者:珍珠、奶盖、椰果、红豆等

被装饰者和装饰者一同实现一个饮料接口。
接口有一个 花费方法(cost),有一个price,自身价格

装饰者持有一个被装饰者对象,在调用cost方法时返回被装饰者的cost+装饰者的price。

java 中实例: FilterInputStream,FilterOutputStream,BufferedInputStream,BufferedOutputStream

// 饮料接口,有一个cost方法。(如果有比较多相同元素,可以使用抽象类,减少代码量)
public interface Beverage {
    // 计算价格的抽象方法!
    Double cost();
}

// 奶茶:被修饰类,实现饮料接口
public class MilkTea implements Beverage{
    private String name = "奶茶";
    private Double price = 10.0;
    public MilkTea() {
    }
    @Override
    public Double cost() {
        return price;
    }
}

// 珍珠类:修饰类,持有被修饰的饮料引用。
public class Pearl implements Beverage {
    private String name = "珍珠";
    private Double price = 3.0;
    private Beverage beverage;
    public Pearl(Beverage beverage) {
        this.beverage = beverage;
    }
    public Pearl() {
    }
    @Override
    public Double cost() {
        return beverage.cost() + price;
    }
}
// 双份珍珠的奶茶价格!3+3+10=16
public static void main(String[] args) {
    Beverage beverage = new Pearl(new Pearl(new MilkTea()));
    System.out.println(beverage.cost());
}

// 打印结果
16.0
Process finished with exit code 0

适配器模式

概述:作为两个不兼容的接口之间的桥梁。将自己无法完成的事通过接口调用能解决该事的另一个对象来处理。
举例:手机充电需要20V的电压,但中国家用电压为220V,这时需要一个变压器,将220V的电压转化为20V供手机充电。

public class Test {
   public static void main(String[] args) {
       Phone phone = new Phone();
       VoltageAdapter adapter = new VoltageAdapter();
       phone.setAdapter(adapter);
       phone.charge();
   }
}

// 手机类
class Phone {

   public static final int V = 220;// 正常电压220v,是一个常量

   private VoltageAdapter adapter;

   // 充电
   public void charge() {
       adapter.changeVoltage();
   }

   public void setAdapter(VoltageAdapter adapter) {
       this.adapter = adapter;
   }
}

// 变压器
class VoltageAdapter {
   // 改变电压的功能
   public void changeVoltage() {
       System.out.println("正在充电...");
       System.out.println("原始电压:" + Phone.V + "V");
       System.out.println("经过变压器转换之后的电压:" + (Phone.V - 200) + "V");
   }
}

运行结果:
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值