专栏名称: 邪笑风
devops工程师
目录
相关文章推荐
金融博驿  ·  2024.9.16 美股大盘复盘 ·  3 天前  
金融博驿  ·  2024.9.16 美股大盘复盘 ·  3 天前  
丫丫港股圈  ·  那些腰斩的美股明星股 ·  6 天前  
51好读  ›  专栏  ›  邪笑风

java开发面试问答----设计模式篇

邪笑风  · 掘金  ·  · 2019-10-12 06:54

正文

阅读 15

java开发面试问答----设计模式篇

原则

  • 开闭原则:可扩展,不可修改
  • 里氏代换原则:基类能出现的地方子类一定能出现
  • 单一职责原则:一个类应该只有一种职责
  • 依赖倒转原则:依赖于抽象而不是实现,面向接口编程
  • 接口隔离原则:每个接口不存在子类用不到的方法
  • 迪米特原则(最少知道):陌生的类不作为局部变量出现在类中而是直接朋友,直接朋友为成员变量,方法参数,方法返回值
  • 合成复用原则:尽量使用合成/聚合,而不是继承

创建模式

简单工厂

  • 对需要生成的类进行抽象,即一个工厂类可以生产出同一接口的不同对象

抽象工厂

  • 对需要生成的类和工厂都进行抽象,即同一接口的不同工厂类生产出对应的同一接口的不同对象

builder模式

  • 当类的属性大部分可为空时使用建造者模式,通过一个builder类按需组合出对象

单例模式

  • 饿汉模式:静态变量,在类初始化时即完成对象的初始化
  • 饱汉模式:在调用生产类方法时才初始化对象,延迟加载
    • 针对多线程问题, 采用双重锁;
    • synchronized 保证多线程时只有一个线程能进行初始化即原子性;
    • voliate 保证有序性和可见性,java1.6之后才出现
    • 什么是原子性,有序性,可见性?
      • cpu执行命令时为了提高性能会将内存中的数据读取到高速缓存中,在高速缓存中计算后再写回主存,由于每个cpu核的高速缓存是不一样的,所以多线程时就会出现各种一致性问题
      • 原子性是指一个操作或者连续多个操作要么执行完要么不执行
      • 可见性是指当一个线程修改了该参数的值时其他线程要能够立刻看到该参数的值
      • 有序性是指cpu在执行命令时会发生指令重排序并保证最终一致,但在多线程中指令重排序会引起参数判断错误
public class Demo {
	private final voliate DemoClass demoClass = null;
	
	public static DemoClass getInstance(){
		if (demoClass == null){
			synchronized(DemoClass.class){
				if (demoClass == null){
					demoClass = new DemoClass;
				}
			}
		}
		return demoClass;
	}
}
复制代码

原型模式

  • 实现Cloneable的接口,可以通过克隆生产新的对象
  • 深拷贝:对象中的基本类型和引用类型全部都是重新创建的
  • 浅拷贝:对象中的基本类型是重新创建的,引用类型还是指向原来的对象

结构模式

适配器模式

  • 将某个类的接口转换成期望的另一个接口
  • 创建一个适配器类继承旧类的功能再扩展出新的功能或者直接加工出新功能
public interface DemoA {
	String getA();
}
public class A implements DemoA
public interface DemoB {
	String getA();
	String getB();
}
//类适配器, 具有同样的方法,接口少变多
public class adapter extends A implements DemoB {
	String getB(){
	}
}
//对象适配器,老接口功能需要重置
pulic class adapter2 implements DemoB{
 	private A a;
 	String getA(){modify(a.getA())}
 	String getB(){}
}
//接口适配器, 仅重置老部分接口功能
public abstract class adapter3 implements DemoB {
	String getA(){}
	String getB(){}
}
public class subAdapter3 extend B3 {
	String getA(){}
}
复制代码

装饰器模式

  • 修改原对象的功能而不修改原对象,装饰器和原对象实现同一种接口,例子:io类
public interface DemoA {
	String getA()
}
public class Old implements DemoA
public class Decorator implements DemoA {
	private Old old;
	public Decorator (Old old){
		this.Old = old;
	}
	String getA() {
		xxxx;
		old.getA()
	}
}
new Decorator(new Decorator(new Old()))
复制代码

代理模式

  • 通过代理实现行为,代理模式和装饰器模式实现基本一样,唯一区别是代理模式能控制原对象的行为而装饰器模式仅修饰原对象的行为
public class Agent implements DemoA {
	private Old old;
	public Agent (Old old){
		this.Old = old;
	}
	String getA() {
		if (xxx) {
			old.getA()			
		}
	}
}
new Agent(new Old())
复制代码

外观模式

  • 组合多个类的同一种方法, 解决类之间的依赖关系
public class A {
	String start(){}
}
public class B {
	String start(){}
}
public class Facade {
	String start(){
		A.start()
		B.start()
	}
}
复制代码

桥接模式

  • 当一个类有多个维度变换时, 使用桥接模式模式进行维度间的解耦, 将继承关系转换成聚合关联关系
public abstract class Shape{
   private Color color
	public void setColor(Color color){
		color = color;
	}
	public abstract void draw();
}
public class Circle extends Shape {
	public void draw (){
		color.paint(this)
	}
}
public class Square extends Shape {
	public void draw (){
		color.paint(this)
	}
}
public interface Color {
	void paint (Shape shape)
}
public class Red implements Color
public class Black implements Color
Circle.setColor(new Red())
Circle.draw()

复制代码

组合模式

  • 专门处理树形结构, 比如文件夹中有文件夹也有文件, 在整体与部分的层次结构中希望忽略整体与部分的差异
public abstract class TreeNode {
	void add(TreeNode treeNode){}
	void delete(TreeNode treeNode){}
	void getName(){}
	void operation(){}
}
public class File extends TreeNode {
	void getName(){}
	void operation(){}
}
public class Dir extends TreeNode {
   private List<TreeNode> nodes = new ArrayList<>() 
	void add (TreeNode treeNode){}
	void delete (TreeNode treeNode){}
	void getName(){}
	void operation(){
		for (TreeNode node : nodes){
			node.operation()
		}
	}
}
复制代码

享元模式

  • 共享对象, 例子:线程池
public class ConnectPool {
	private final Vector<Connect> pool = new Vector<Connect>(size)
	
	public synchronized static Connect getConnect(){
		if (pool > 0){
			Connect c = pool.get(0);
			pool.remove(c);
			return c;
		} else {
			Connect c = new Connect;
			pool.add(c);
			return c;
		}
	}
}
复制代码

行为模式

父类和子类

策略模式

  • 封装算法行为, 同一抽象类有多个子类需要选择,子类里面封装的是不同的算法
  • 和简单工厂模式的区别,简单工厂模式封装了选择过程,而策略模式返回的是单个的策略,选择过程需要自己实现,工厂模式是黑盒,策略模式是白盒

模板方法模式

  • 抽象类制作模板实现共同的步骤,子类根据需要重写抽象类的行为

两个类

观察者模式

  • 一个对象变化时,通知依赖该对象的对象变化,该对象管理所有的观察者,即通知行为
public class Pub {
	private Vector<Observer> observers = new Vector<>();
	public void add(Observer ob){
		observers.add(ob)
	}
	public void remove(Observer ob){
		observers.remove(ob)
	}
	public void operation(){
	   xxxx;
		notify();
	}
	private void notify(){
		Enumeration<Observer> obs = observers.elements();
		for (Observer ob : obs){
			ob.update()
		}
	}
	
}
public class Sub{
	public void update()
}
复制代码

迭代器模式

  • 屏蔽集合底层的实现,使用迭代器统一遍历行为
public class Collection {
	Object[] ts;
	public Iterator iterator(){
		return new Iterator(this)
	}
	public Object get(int i){
		return ts[i]
	}
	public int size(){
		return ts.length
	}
}
public class Iterator {
	private int cursor = -1;
	private Collection demos;
	public Iterator(Collection collection){
		this.demos = collection
	}
	public bool hasNext() {
		if (cursor < demos.size - 1){
			return true;
		}
		return false;
	}
	public Demo next(){
	   if (cursor < demos.size() - 1){
			cursor = cursor + 1;	   
	   }
		return demos.get(cursor);
	}
}
复制代码

命令模式

  • 实现命令发布者和命令接受者的解耦,是对命令的抽象,有利于扩展和控制命令
public class General {
	private Command command
	public void send(){
		command.exec()
	}
}
public class Command {
	private Soldier soldier
	public void exec(){
		soldier.action()
	}

}
public class Soldier {
	public void action()
}
复制代码

责任链模式

  • 请求发送者不用在乎命令在哪一步执行, 可以动态控制链中的实现
  • servlet的filter功能保持了一个filter集合
  • dubbo的filter功能是使用链表实现,每一链保持后一链的信息,最后一个是final

类的状态

备忘录模式

  • 保持对象的某个状态,在必要时候进行恢复,如游戏存档,control+z
  • 发起人:创建备忘录,保存状态到备忘录,从备忘录恢复状态
  • 备忘录管理者:存档备忘录,提出备忘录
  • 备忘录:记录发起人的状态

状态模式

  • 通过改变状态改变行为,将与状态有关的行为放到状态类中实现,如qq的隐身不可见上线可见
  • 状态模式的实现和策略模式完全一样,不同点在于策略模式是让用户自己选择何种算法,而状态模式可以自动切换状态
public class WaterDispenser {
	private int capacity = 20
	private State state
	public Water press(){
		capacity --;
		if (capacity <= 0) {
			state = new Nullstate()
		}
		return state.press()
	}
}
public interface State {
	Water press()
}
public class NullState implements State {
	public Water press () {
		return null
	}
}
public class FullState implements State {
	public Water press () {
		return new Water()
	}
}
WaterDispenser waterDispenser = new WaterDispenser(new Fullstate)
waterDispenser.press()
复制代码

中间类

访问者模式

  • 如果对象结构稳定,而要不修改对象的情况下修改操作就可以使用访问者模式
  • 如账单系统,账单对象只有收入和支出,而针对不同的角色需要不同的统计手段

中介模式

  • 用一个中介对象封装多个对象间的交互,减少对象间的耦合
  • 中介模式和代理模式:代理模式是代理单个对象的行为,中介模式是管理多个对象间的行为
  • 中介模式和外观模式:外观模式的子系统不知道外观类的存在,而中介模式中同事类知道中介类的存在
public abstract class User {
	void buyHouse()
	void sellHouse()
}
public class Buyer implements User {
	private Intermediary intermediary
	public void buyHouse () {
		intermediary.buyHouse()
	}
	public void call(String message) {}
}
public class Seller implements User {
	private Intermediary intermediary
	public void sellHouse () {
		intermediary.sellHouse()
	}
	public void call(String message) {}	
}
public class Intermediary implements User {
	private Buyer buyer;
	private Seller seller;
	public void buyHouse() {
		seller.call("卖吗")
	}
	public void sellHouse()	{
		buyer.call("买吗")
	}
}

复制代码

解释器模式

  • 用于sql和表达式解析,用解释器对象封装两种语言间的对应关系,如+-的执行