设计模式
设计模式的SOLID原则
这篇文章主要会介绍几种常见的设计模式,以帮助更好的应对面试中可能会遇到的有关设计模式的问题。设计模式中有一个SOLID原则,分别是单一原则、开闭原则、里氏替换原则、接口隔离原则、依赖倒置原则。遵循这5个原则可以使程序做到高内聚,低耦合,更加健壮。
-
单一责任原则:一个类或者一个方法只做一件事,降低耦合。
-
开放封闭原则:一个类或者接口应该对扩展开放,对修改关闭。

-
里氏替换原则:子类可以扩展父类的功能,但是不能改变父类原有的功能。
-
接口隔离原则:类不应该依赖不需要的接口。
-
依赖倒置原则:高级模块不应该依赖低级模块,而是依赖抽象。抽象不能依赖细节,而是细节需要依赖抽象。
1.简单工厂模式
简单工厂模式通常就是一个工厂类 XxxFactory,里面有一个静态方法,根据我们不同的参数,返回不同的派生自同一个父类(或实现同一接口)的实例对象。
public class FoodFactory {
public static Food makeFood(String name) {
if (name.equals("noodle")) {
Food noodle = new LanZhouNoodle();
noodle.addSpicy("more");
return noodle;
} else if (name.equals("chicken")) {
Food chicken = new HuangMenChicken();
chicken.addCondiment("potato");
return chicken;
} else {
return null;
}
}
}
2.工厂模式
如果在创建对象的时候需要使用两个或者两个以上的工厂,就需要用到工厂设计模式。工厂设计模式是在简单工厂设计模式的基础上的再一次抽象。如下,ChineseFoodA、ChineseFoodB、AmericanFoodA、AmericanFoodB 都派生自 Food。工厂模式将对象的创建过程和对象的使用方法进行隔离,实现了解耦合。
public interface FoodFactory {
Food makeFood(String name);
}
public class ChineseFoodFactory implements FoodFactory {
@Override
public Food makeFood(String name) {
if (name.equals("A")) {
return new ChineseFoodA();
} else if (name.equals("B")) {
return new ChineseFoodB();
} else {
return null;
}
}
}
public class AmericanFoodFactory implements FoodFactory {
@Override
public Food makeFood(String name) {
if (name.equals("A")) {
return new AmericanFoodA();
} else if (name.equals("B")) {
return new AmericanFoodB();
} else {
return null;
}
}
}
在客户端调用时:
public class APP {
public static void main(String[] args) {
// 先选择一个具体的工厂
FoodFactory factory = new ChineseFoodFactory();
// 由第一步的工厂产生具体的对象,不同的工厂造出不一样的对象
Food food = factory.makeFood("A");
}
}
使用场景:
BeanFactory
3.单例模式
单例非为饿汉式单例模式和饱汉式单例模式,差别在于创建实例的时间。
饿汉式:
public class Singleton {
// 首先,将 new Singleton() 堵死
private Singleton() {};
// 创建私有静态实例,意味着这个类第一次使用的时候就会进行创建
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
// 瞎写一个静态方法。这里想说的是,如果我们只是要调用 Singleton.getDate(...),
// 本来是不想要生成 Singleton 实例的,不过没办法,已经生成了
public static Date getDate(String mode) {return new Date();}
}
DCL饱汉式:
public class Singleton {
// 首先,也是先堵死 new Singleton() 这条路
private Singleton() {}
// 和饿汉模式相比,这边不需要先实例化出来,注意这里的 volatile,它是必须的
private static volatile Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
// 加锁
synchronized (Singleton.class) {
// 这一次判断也是必须的,不然会有并发问题
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
嵌套类:该单例创建方式最经典,推荐使用。
public class Singleton3 {
private Singleton3() {}
// 主要是使用了 嵌套类可以访问外部类的静态属性和静态方法 的特性
private static class Holder {
private static Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance() {
return Holder.instance;
}
}
使用场景:Spring下默认的bean均为singleton
4.模板方法模式
模板方法模式就是有一个抽象类,抽象类中包含了一个模板方法和其他的抽象方法或者正常的方法,抽象的方法由继承的类去实现,实现类通过调用模板方法完成了方法的组合调用和自由实现。也就是说,模板方法只负责定义第一步应该要做什么,第二步应该做什么,第三步应该做什么,至于怎么做,由子类来实现。
public abstract class AbstractTemplate {
// 这就是模板方法
public void templateMethod(){
init();
apply(); // 这个是重点
end(); // 可以作为钩子方法
}
protected void init() {
System.out.println("init 抽象层已经实现,子类也可以选择覆写");
}
// 留给子类实现
protected abstract void apply();
protected void end() {
}
}
实现类:
public class ConcreteTemplate extends AbstractTemplate {
public void apply() {
System.out.println("子类实现抽象方法 apply");
}
public void end() {
System.out.println("我们可以把 method3 当做钩子方法来使用,需要的时候覆写就可以了");
}
}
使用场景:spring中的JdbcTemplate
5.策略模式
策略模式是一种比较常见的设计模式,策略模式中先定义一个策略接口,再定义几个实现了策略接口的类。最后还需要定义一个使用策略的类,如下:
策略接口:
public interface Strategy {
public void draw(int radius, int x, int y);
}
实现了策略接口的类:
public class RedPen implements Strategy {
@Override
public void draw(int radius, int x, int y) {
System.out.println("用红色笔画图,radius:" + radius + ", x:" + x + ", y:" + y);
}
}
public class GreenPen implements Strategy {
@Override
public void draw(int radius, int x, int y) {
System.out.println("用绿色笔画图,radius:" + radius + ", x:" + x + ", y:" + y);
}
}
public class BluePen implements Strategy {
@Override
public void draw(int radius, int x, int y) {
System.out.println("用蓝色笔画图,radius:" + radius + ", x:" + x + ", y:" + y);
}
}
使用策略的类:
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeDraw(int radius, int x, int y){
return strategy.draw(radius, x, y);
}
}
使用示例:
public static void main(String[] args) {
Context context = new Context(new BluePen()); // 使用绿色笔来画
context.executeDraw(10, 0, 0);
}
使用场景:spring中在实例化对象的时候用到Strategy模式在SimpleInstantiationStrategy中有如下代码说明了策略模式的使用情况:
6.代理模式
代理模式也是比较常见的一种设计模式,在Spring的AOP源码中有使用。代理模式中,首先需要有一个接口和接口的实现类,代理类同样实现了接口,并且在实现需要被代理的方法前后做了相应的增强,中间是调用需要被代理的对象的方法。
接口:
public interface FoodService {
Food makeChicken();
Food makeNoodle();
}
接口的实现类:
public class FoodServiceImpl implements FoodService {
public Food makeChicken() {
Food f = new Chicken()
f.setChicken("1kg");
f.setSpicy("1g");
f.setSalt("3g");
return f;
}
public Food makeNoodle() {
Food f = new Noodle();
f.setNoodle("500g");
f.setSalt("5g");
return f;
}
}
代理类:同样实现了接口,内部需要注入一个接口实现类的实例对象。
// 代理要表现得“就像是”真实实现类,所以需要实现 FoodService
public class FoodServiceProxy implements FoodService {
// 内部一定要有一个真实的实现类,当然也可以通过构造方法注入
private FoodService foodService = new FoodServiceImpl();
public Food makeChicken() {
System.out.println("我们马上要开始制作鸡肉了");
// 如果我们定义这句为核心代码的话,那么,核心代码是真实实现类做的,
// 代理只是在核心代码前后做些“无足轻重”的事情
Food food = foodService.makeChicken();
System.out.println("鸡肉制作完成啦,加点胡椒粉"); // 增强
food.addCondiment("pepper");
return food;
}
public Food makeNoodle() {
System.out.println("准备制作拉面~");
Food food = foodService.makeNoodle();
System.out.println("制作完成啦")
return food;
}
}
使用示例:
// 这里用代理类来实例化
FoodService foodService = new FoodServiceProxy();
foodService.makeChicken();

使用场景:spring的Proxy模式在aop中有体现,比如JdkDynamicAopProxy和Cglib2AopProxy。

浙公网安备 33010602011771号