心灵鸡汤:

加载中...

面试官老问我设计模式

什么是设计模式

  • 通俗来讲,设计模式是一些前人,一些大佬们从一次次的失败中总结出来的一种解决问题的方案。
  • java中的23种设计模式简单的脑图

设计模式的几大原则

  • 开闭原则:对扩展开放,对修改关闭。(即可新增代码,但不要修改原有的代码。)
  • 里氏代换原则:继承的时候,子类可以扩展父类或者超类的功能,但是不要改父类的方法和功能等等。
  • 依赖倒置原则:指面向接口编程,而不是面向实现编程
  • 单一职责原则:一个方法或者一个类,尽量只负责做一个职责。
  • 接口隔离原则:为系统中各个类建立它们对应的专用接口,每一个接口应该承担一种相对独立的角色,接口要做的事它就做,不要做的它就不做。
  • 迪米特法则:(最少知道原则)只与你的直接朋友交谈,不和”陌生人“交谈(A->B->C,其中,A的直接朋友是B,B的直接朋友是C,A和C可理解为陌生人,此时如果A要向C通信拿数据,则可以通过B来操作,B可理解为中间件)
  • 合成复用原则:它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

常见设计模式

单例模式

只能有一个自己的对象实例,所以叫单例。

懒汉式(没加synchronized所以线程不安全,因为它很懒,所以需要时才创建对象)

public class Lazy {

    private static Lazy lazy;
    //这里使用私有的构造方法,而不用public(不能被实例化)
    private Lazy() {
    }

    public static Lazy getInstance() {

        if (lazy == null) {
            return new Lazy();
        }
        return lazy;
    }
}

饿汉式(线程安全,因为它很饿,所以虚拟机启动后就马上创建对象,不管你要不要)

public class Hungry {

    private static Hungry hungry = new Hungry();
    //这里使用私有的构造方法,而不用public(不能被实例化)
    private Hungry() {
    }

    public static Hungry getInstance() {
        return hungry;
    }
}

代理模式

现实生活中,每个地方,乡镇等火车票代售点就是官方售票的代理。我们可以不用去到很远的火车站购票,直接在家附近的代售点就可以买票回家了,方便快捷。
++代理分为静态代理和动态代理,静态代理又包括jdk动态代理和cglib动态代理。++

静态代理

购票接口

购票方法

public interface ITicket {

    void ticket();

}

购票接口实现类

我要购票

public class Station implements ITicket {

    @Override
    public void ticket() {
        System.out.println("买一张去广州的火车票");
    }
}

火车站代理

我帮你代理购票

public class StationProxy implements ITicket {

    private Station station;

    //公有的 Station 代理构造方法,拿到 Station 订票的权利
    public StationProxy(Station station) {

        this.station = station;
        System.out.println("我是代理点,我拿到了 Station 订票的权利,可以给你订票");

    }

    @Override
    public void ticket() {

        station.ticket();
        System.out.println("购票成功");

    }

}

测试

购票结果

 Station station = new Station();
 StationProxy stationProxy = new StationProxy(station);
 stationProxy.ticket();

结果

jdk动态代理
购票接口

public interface ITicket {

    void ticket(String str);

}

购票接口实现类

public class Station implements ITicket {

    @Override
    public void ticket(String str) {
        System.out.println("买一张去广州的火车票");
    }
}

动态代理类

//实现InvocationHandler接口,重写invoke方法
public class Dynamic implements InvocationHandler {

    private Object object;

    public Object creatProxy(Object object) {
        //将目标对象传入进行代理
        this.object = object;
        //将代理对象返回 //其中有三个参数
        return Proxy.newProxyInstance(
                object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                this
        );
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //调用前
        before();

        Object invoke = method.invoke(object, args);
        //调用后
        after();
        return invoke;
    }

    private void before() {
        System.out.println("调用前......");
    }

    private void after() {
        System.out.println("调用后");
    }
}

测试

Dynamic dynamic = new Dynamic();
ITicket proxy = (ITicket)dynamic.creatProxy(new Station());
proxy.ticket("par");

结果:

工厂模式

!>简单工厂模式

描述花的接口

public interface IFlower {
    String describe();
}

玫瑰花类

public class Rose implements IFlower{
  @Override
  public String describe() {
        System.out.println("我是玫瑰花");
        return "我是玫瑰";
    }
}

百合花类

public class Lily implements IFlower {
  @Override
  public String describe() {
        System.out.println("我是百合花");
        return "我是百合";
    }
}

工厂类一

public class FlowerFactory {

    public static Rose creatRose(){
        Rose rose = new Rose();
        return rose;
    }

    public static Lily creatLily(){
        Lily lily = new Lily();
        return lily;
    }
}

测试

Lily lily = FlowerFactory.creatLily();
String lilyDesc = lily.describe();
Rose rose = FlowerFactory.creatRose();
String roseDesc = rose.describe();

第二种工厂类方法,传入一个对应的花名的参数,在工厂类中作判断,然后生产出对应的花。
工厂类二

//传入一个参数,工厂制造一个对应的产品 
public static IFlower create(String name){
    if("lily".equals(name)){
        return new Lily();
    }else if("rose".equals(name)){
        return new Rose();
    }
    return null;
}

测试

IFlower rose = FlowerFactory.create("rose");
String describe = rose.describe();

!>工厂方法模式(日常开发中常用)

前面的简单工厂模式,所有的产品都是在同一个工厂生产的,不是很友好 ,我们现在用工厂模式,分别为每个品种开一个工厂。

玫瑰工厂

public class RoseFactory {
    public Rose create(){
        return new Rose();
    }
}

百合工厂

public class LilyFactory {
    public Lily create(){
        return new Lily();
    }
}

测试

RoseFactory roseFactory = new RoseFactory();
Rose rose = roseFactory.create();
String roseDesc = rose.describe();

LilyFactory lilyFactory = new LilyFactory();
Lily lily = lilyFactory.create();
String lilyDesc = lily.describe();

!> 抽象工厂模式

适用于横向增加同类工厂,不适合新增功能这样的纵向扩展。
总工厂接口

public interface IFactory {
    IFlower instance();
}

玫瑰工厂

//玫瑰工厂实现总工厂接口
public class RoseFactory implements IFactory {
  @Override
  public IFlower instance(){
        return new Rose();
    }
}

百合工厂

//百合工厂实现总工厂接口
public class LilyFactory implements IFactory {
  @Override
  public IFlower instance() {
        return new Lily();
    }
}

测试

IFactory roseFactory = new RoseFactory();
IFlower rose = roseFactory.instance();
String roseDesc = rose.describe();

IFactory lilyFactory = new LilyFactory();
IFlower lily = lilyFactory.instance();
String lilyDesc = lily.describe();

策略模式

适用于策略少于等于4个的时候,太多策略会造成策略膨胀。

数学加减法接口

public interface IMath {

    public int addOrSub(int a, int b);

}

加法类

//加法类实现IMath接口
public class Add implements IMath {

  @Override
  public int addOrSub(int a, int b) {

        return a + b;
    }
}

减法类

//减法类实现IMath接口
public class Sub implements IMath {

  @Override
  public int addOrSub(int a, int b) {

        return a - b;
    }
}

计算类

public class Calculated {
    
    private IMath iMath;
    
    public Calculated(IMath iMath) {

        this.iMath = iMath;

    }

    //开始计算
  public int startCal(int a, int b) {

        return iMath.addOrSub(a, b);
    }

}

测试

//构造计算类时候,通过传递的参数确定是加法还是减法
Calculated addCal = new Calculated(new Add());
int add = addCal.startCal(3, 2);

Calculated subCal = new Calculated(new Sub());
int sub = subCal.startCal(1, 10);

观察者模式

观察者模式和发布订阅模式有点类似,区别在于前者只有两个对象(观察者和被观察者),后者有三个对象(发布者、Broker和订阅者),多了一个中转站。

监听消息接口

public interface IListener {
    void onListen(String message);
}

观察者1

public class LaoWang implements IListener {

  @Override
  public void onListen(String message){
        System.out.println("我是隔壁老王,收到了Observe发布的消息:"+"{"+message+"}");
    }
}

观察者2

public class LaoWu implements IListener {

    @Override
  public void onListen(String message) {
        System.out.println("我是隔壁老吴,收到了Observe发布的消息:" + "{" + message + "}");
    }
}

被观察者

public class Observe {

    List<IListener> listeners = new ArrayList<IListener>();

    //通过传入对应的订阅者,开始订阅Observe
public void addListener(IListener iListener) {
    listeners.add(iListener);
    }

    //Observe向观察者集合listeners发消息
  public void sendMessage() {
        listeners.forEach(obj -> {
        obj.onListen("我是Observe推送过来的消息体");
        });
    }
}

测试

Observe observe = new Observe();

//老王订阅Observe
Observe observe.addListener(new LaoWang());

//Observe向订阅者发消息 
observe.sendMessage();

结果:

//控制台打印:
//我是隔壁老王,收到了Observe发布的消息:{我是Observe推送过来的消息体}

装饰者模式

理解起来有点绕,参考链接1
参考2

适配器模式

定义:把一个类的接口变换成客户端所期待的另一种接口,使得原本因接口不匹配而无法在一起工作的两个类可以一起工作,即系统只有220伏的接口,我现在要用110伏,所以适配器就产生了,通过适配器把220转成110伏。
角色组成:源角色=>适配器=>目标角色

  • 类适配器模式

中国标准电压类

public class HighVoltage {

  public int chinaVoltage() {
        int voltage = 220;
        return voltage;
    }
}

高转低电压接口

public interface IHighToLow {

    int change();
}

类适配器

//继承源角色并实现目标角色
public class Adapter extends HighVoltage implements IHighToLow {

    @Override
    public int change() {
        //获取中国标准电压
        int china = chinaVoltage();

        //电压转换
        int change = china / 2;
        System.out.println("转换后的电压是:" + change + "伏");

        return change;
    }
}

测试

//输出:转换后的电压是:110伏
  • 对象适配器模式
    对象适配器类
    适配器实现转电压接口,重写转换方法。构造适配时,传入一个HighVoltage对象。
public class ObjAdapter implements IHighToLow {

    private HighVoltage highVoltage;

    public ObjAdapter(HighVoltage highVoltage) {
        this.highVoltage = highVoltage;
    }
    
    @Override
    public int change() {
        //获取中国标准电压
        int china = highVoltage.chinaVoltage();
        //电压转换
        int change = china / 2;
        System.out.println("转换后的电压是:" + change + "伏");
        return change;
    }
    
}

Template模板模式

例如:RedisTemplate、JdbcTemplate等模板,可封装不变部分,扩展可变部分,提取公共代码,便于维护,行为由父类控制,子类实现。

游戏抽象类

//游戏抽象类,不能实例化new,只能由子类实现行为
public abstract class Game {

    abstract void init();

    abstract void start();

    abstract void end();
    //因模板是固定不变的,所以用final修饰
    public final void play() {

        init();
        start();
        end();
    }

}

玩王者模板类

public class WangZhe extends Game {

    @Override
  void init() {
        System.out.println("初始化王者");
    }

    @Override
  void start() {
        System.out.println("我开始打王者");
    }

    @Override
  void end() {
        System.out.println("我退出了王者");
    }
}

玩吃鸡模板类

public class ChiJi extends Game {

    @Override
  public void init(){
        System.out.println("初始化吃鸡");
    }

    @Override
  public void start(){
        System.out.println("我开始玩吃鸡");
    }

    @Override
  public void end(){
        System.out.println("我退出了吃鸡");
    }
}

测试

Game wangZhe = new WangZhe();
wangZhe.play();
//控制台打印结果:
//初始化王者
//我开始打王者
//我退出了王者

由测试结果可知,模板模式常用来解决固定的一系列操作,比如jdbc连接数据库的步骤分为:1.加载驱动 =》2.创建连接 =》3.预处理 =》4.执行sql语句 =》5.关闭jdbc连接流

posted @ 2025-03-20 15:21  Mosey  阅读(32)  评论(0)    收藏  举报
TOP