说一下你知道的设计模式有哪些?
下面3种类型种各挑几个常见的或者你用过的说就够了
创建型模式:
单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式
结构型模式:
适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
行为型模式:
模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、策略模式、职责链模式、接解释器模式、状态模式、访问者模式
工厂方法模式和抽象工厂模式有什么区别?
工厂方法模式:
一个抽象产品类,能够派生出多个具体产品类,一个抽象工厂类,能够派生出多个具体工厂类,每个具体工厂类只能建立一个具体产品类的实例
抽象工厂模式:
多个抽象产品类,每一个抽象产品类能够派生出多个具体产品类,一个抽象工厂类,能够派生出多个具体工厂类,每个具体工厂类能够建立多个具体产品类的实例
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个,工厂方法模式的具体工厂类只能建立一个具体产品类的实例,而抽象工厂模式能够建立多个
JDK种用了那些设计模式
几乎每一种设计模式都被用到了JDK的源码中,下面列举一些常见的:
抽象工厂模式
javax.xml.parsers.DocumentBuilderFactory#newInstance()
javax.xml.transform.TransformerFactory#newInstance()
建造者模式
java.lang.StringBuilder#append()
java.lang.StringBuffer#append()
原型模式
java.lang.Object#clone()
适配器模式
java.util.Arrays#asList()
java.util.Collections#list()
装饰器模式
IO 流的子类
java.util.Collections#synchronizedXXX()
享元模式
java.lang.Integer#valueOf(int)
代理模式
java.lang.reflect.Proxy
javax.inject.Inject
责任链模式
java.util.logging.Logger#log()
javax.servlet.Filter#doFilter()
Spring中用到了那些设计模式?
- 单例设计模式:Spring中的Bean默认都是单例的
- 代理设计模式:Spring AOP功能的实现
- 工厂设计模式:Spring使用工厂模式经过BeanFactory,ApplicationContext建立Bean对象
- 模板方法模式:Spring中jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就是用到了模板模式
- 装饰器设计模式:咱们的项目须要链接多个数据库,并且不一样的客户在每次访问中根据须要会去访问不一样的数据库。这种模式让咱们能够根据客户的需求可以动态切换不一样的数据源
- 观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用
- 适配器模式:SpringAOP的加强或通知(Advice)使用到了适配器模式,SpringMVC中也是用到了适配器模式适配Controller
设计模式六大原则:
- 单一职责原则:一个方法一个类只负责一个职责,各个职责的程序改动,不影响其他程序
- 开闭原则:对扩展开发,对修改关闭,即在不修改一个软件实体的基础上去扩展其余功能
- 里氏代换原则:在软件系统中,一个能够接受基类对象的地方必然能够接受一个子类对象
- 依赖倒转原则:针对于接口编程,依赖于抽象而不依赖于具体
- 接口隔离原则:使用多个隔离的接口取代一个统一的接口,下降类与类之间的耦合度
- 迪米特原则:一个实体应当尽可能少的与其余实体之间发生相互作用,是的系统功能模块相对独立
单例模式的优缺点:
优势:
因为在系统内存中只存在一个对象,所以能够节约系统资源,对于一些要频繁建立和销毁的对象单例模式无疑能够提升系统的性能
缺点:
因为代理模式中没有抽象层,所以单例类的扩展有很大的困难。滥用单例将带来一些负面的问题,如为了节省资源将数据库链接对象设计为的单例类,可能会致使共享链接池对象的程序过多而出现连接池的溢出;若是实例化的对象长时间不被利用,系统会认为垃圾而被回收。这价格致使对象状态的丢失
手写一下单例模式?
懒汉式:用到时再去建立
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 synchronized Singleton getInstance(){
return instance;
}
}
静态内部类(推荐)
public class Singleton {
private static class SingletonHolder{
private static final Singleton INSTTANCE = new Singleton();
}
private Singleton(){};
private static final Singleton getInstance(){
return SingletonHolder.INSTTANCE;
}
}
双重校验锁【推荐】
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;
}
}
请说一下观察者模式
消息队列(MQ),一种能实现生产者到消费者单向通信的通信模型,这也时现在常用的主流中间件,常见有RabbitMQ、ActiveMQ、kafka等,他们的特点也有很多比如:解耦,异步,广播,削峰等等多种优势特点。
在设计模式中也有一种模式能有效的达到解耦、异步的特点,那就是观察者模式又称为发布订阅模式
举一个例子,就好比微信朋友圈,以当前个人作为订阅者,好友作为主题,一个人发一条动态朋友圈出去,他们的好友都能看到这个朋友圈,并且可以在自主选择点赞或者评论
- Subject(主题):主要由类实现的可观察的接口,通过观察者使用attach方法,以及取消观察的detach方法
- ConcreteSubject(具体主题):是一个实现主题接口的类,处理观察者的变化
- Observe(观察者):观察者是一个抽象类或者接口,根据主题中的更改而进行更新。
public interface Subject {
//添加订阅关系
void attach(Observer observer);
//移除订阅关系
void detach(Observer observer);
//通知订阅者
void notifyObservers(String message);
}
先创建一个主题定义,定义添加删除关系以及通知订阅者
public class ConcreteSubject implements Subject{
//订阅者容器
private List<Observer> observers = new ArrayList<Observer>();
@Override
public void attach(Observer observer) {
//添加订阅关系
observers.add(observer);
}
@Override
public void detach(Observer observer) {
//移除订阅关系
observers.remove(observer);
}
@Override
public void notifyObservers(String message) {
//通知订阅者们
for (Observer observer : observers) {
observer.update(null,message);
}
}
}
其次在创建的具体主题,并且构建一个容器来维护订阅关系,支持添加删除关系,以及通知订阅者
public interface Observer {
void update(String message);
}
创建一个观察者接口,方便我们管理
public class FriendOneObserver implements Observer{
@Override
public void update(String message) {
// 模拟处理业务逻辑
System.out.println("friendOne 知道了你发动态了"+message);
}
}
最后就是创建具体的观察者类,实现观察者接口的update方法,处理本身的业务逻辑
public class Test {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
//这里假设添加好友
subject.attach(new FriendOneObserver());
FriendOneObserver twoOvserver = new FriendOneObserver();
subject.attach(twoOvserver);
//发送朋友圈
subject.notifyObservers("第一个朋友圈");
//输出结果: friendOne 知道了你发动态了第一个朋友圈
// friendTwo 知道了你发动态了第一个朋友圈
//这里发现 twoOvserver 是个推荐卖茶叶的,删除好友
subject.detach(twoOvserver);
subject.notifyObservers("第二个朋友圈消息");
//输出结果:friendOne 知道了你发动态了第二个朋友圈消息
}
}
最后就是看测试结果了,通过ConcreteSubject维护了一个订阅关系,在通过notifyObservers方法通知订阅者之后,观察者都获取到消息从而处理自己的业务逻辑
说一下策略模式?
定义一系列算法,封装每个算法,并使他们可以互换,不同的策略可以让算法独立于使用它们的客户而变化。策略模式是属于行为型设计模式,主要是针对不同的策略做出对应行为,达到行为解偶
- Strategy (抽象策略) : 抽象策略类,并且定义策略执行入口
- ConcreteStrategy (具体策略) : 实现抽象策略,实现algorithm方法
- Context (环境):运行特定的策略类
举个例子,汽车的不同档(concreteStrategy)就好比不同的策略,驾驶者选择几档则汽车按几档的速度前进,整个选择权在驾驶者(context) 手中。
public interface GearStrategy {
//定义策略执行方法
void algorithm(String param);
}
这里是用接口的形式,还有一种方式可以用抽象方法abstract来写也是一样的,具体就看大家自己选择了
public abstract class GearStrategyAbstract {
//定义策略执行方法
abstract void algorithm(String param);
}
public class GearStrategyOne implements GearStrategy{
@Override
public void algorithm(String param) {
System.out.println("当前挡位:"+param);
}
}
其次定义具体挡位策略,实现algorithm方法
public class Context {
//缓存所有的策略,当前是无状态的,可以共享策略类对象
private static final Map<String,GearStrategy> strategies = new HashMap<>();
//第一种写法
static {
strategies.put("one", new GearStrategyOne());
}
public static GearStrategy getStrategy(String type){
if (type == null || type.isEmpty()){
throw new IllegalArgumentException("type should not be empty");
}
return strategies.get(type);
}
//第二种写法
public static GearStrategy getStrategySecond(String type){
if (type == null || type.isEmpty()){
throw new IllegalArgumentException("type should not be empty");
}
if (type.equals("one")){
return new GearStrategyOne();
}
return null;
}
public static void main(String[] args) {
//测试结果
GearStrategy strategyOne = Context.getStrategy("one");
strategyOne.algorithm("1档");
//结果:当前挡位1挡
GearStrategy strategyTwo = Context.getStrategySecond("one");
strategyTwo.algorithm("1档");
//结果:当前挡位1挡
}
}
最后就是实现运行时环境(context),你可以定义成StrategyFactory,但都是一个意思
在main方法里面的测试demo,可以看到不同的type类型,可以实现不同的策略,这就是策略模式的主要思想,
在Context里面定义了两种写法:
第一种:时维护了一个strategies的Map容器,用这种方式就需要判断每种策略是否可以共享使用,他只是作为算法的实现。
第二种:是直接通过有状态的类,每次根据类型new一个新的策略类对象,这个就需要根据实际场景去做的判断