GOF 23种设计模式

0 综述

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

在这里插入图片描述

创建型类模式,将对象的部分创建工作延迟到子类,而创建型对象模式则将它延迟到另一个对象中。

结构型类模式,使用继承机制来组合类,而结构型对象模式则描述了对象的组装方式。

行为型类模式,使用继承描述算法和控制流,而行为型对象模式则描述一组对象怎样协作完成单个对象所无法完成的任务。

https://blog.csdn.net/A1342772/article/details/91349142

https://www.cnblogs.com/geek6/p/3951677.html

1单例模式:

懒汉式、饿汉式、双重校验锁、静态加载,内部类加载、枚举类加载。保证一个类仅有一个实例,并提供一个访问它的全局访问点。

package com.patterndesign;

public class Singleton {

    private static volatile Singleton singleton;

    private Singleton() {
    }

    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (singleton) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}


public enum Singleton {

    INSTANCE;

    public void doSomething() {
        System.out.println("doSomething");
    }

}

public class Main {

    public static void main(String[] args) {
        Singleton.INSTANCE.doSomething();
    }

}




在这里插入图片描述

2代理模式:

动态代理和静态代理,什么时候使用动态代理。

2.1 参与者

(1)subject:抽象主题,可以是接口也可以是抽象类,用来进行业务定义。
(2)realsubject:真实主题类,用来实现真正的业务逻辑。
(3)proxy:代理类,也叫委托类。它负责控制对真实主题类访问的控制,将所有抽象主题定义的方法委托给realsubject类实现,并在这个过程加上预处理和善后工作,已达到增强功能的目的
(4)Client:客户端。向处理者提交请求对象。

2.3 类图

在这里插入图片描述

在这里插入图片描述

2.3 实现

public interface Subject {

    void request();

}
public class RealSubject implements  Subject {
    @Override
    public void request() {

    }
}
public class ProxySubject implements Subject {

    private Subject subject;

    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void request() {
        // do someThing
       subject.request();
       //do anther thing
    }
}

public class Client {
    public static void main(String[] args) {
        Subject subject = new ProxySubject(new RealSubject());
        subject.request();
    }
}

java 两种动态代理
https://www.cnblogs.com/daniels/p/8242592.html

3 适配器模式:

将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

3.2 类图

在这里插入图片描述

在这里插入图片描述

4装饰者模式

动态给类加功能。强调组合和委托。比继承灵活,不改变原有对象的情况下给一个对象扩展功能。符合开闭原则

4.1 参与者

1 抽象构件角色(Component):定义一个对象接口或抽象类,可以给这些对象动态地添加职责。

2 具体构件角色(ConcreteComponent):实际被动态地添加职责的对象。

3 抽象装饰者角色(Decorator):实现了Component接口,用来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。

4 具体装饰者角色(ConcreteDecorator):动态地添加职责的对象。

4.2 类图

在这里插入图片描述

在这里插入图片描述

4.3 实现

4.4 参考

https://www.cnblogs.com/mingmingcome/p/9798248.html

5 观察者模式:

有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

5.1 参与者

1.抽象主题(Subject):通常为 抽象类(接口也行),定义一系列操作,如订阅,取消订阅,通知等方法

2.具体主题(Concrete Subject):具体主题,继承或实现抽象主题,实现相应的逻辑,如维护与观察者的关系,将自身的状态变化告知观察者。

3.抽象观察者(Observer):定义观察者行为

4.具体观察者(Concrete Observer):实现观察者行为,实现收到被观察者的通知后将要处理的逻辑

5.2 类图

在这里插入图片描述

在这里插入图片描述

5.3 实现

public interface Observer {
    void update();
}
public class ConcreteObserver1 implements Observer {
    @Override
    public void update() {

    }
}
public class ConcreteObserver2 implements Observer {
    @Override
    public void update() {

    }
}
public abstract class Subject {

    protected List<Observer> observers= new ArrayList<>();
    public  void  attach(Observer observer) {
         observers.add(observer);
    }
    public  void  detach(Observer observer) {
        observers.remove(observer);
    }

    public  abstract void notify1();

}
public class ConcreteSubject extends Subject {
    
    @Override
    public void notify1() {
        for(Observer observer:observers) {
            observer.update();
        }
    }
}

public class Client {

    public static void main(String[] args) {
        Subject  subject= new ConcreteSubject();
        subject.attach(new ConcreteObserver1());
        subject.attach(new ConcreteObserver2());
    //    subject.notify1();
    }

}


5.4 JDK自带的观察者模式:

在 Java 中,通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例。

  1. Observable类
    Observable 类是抽象目标类,它有一个 Vector 向量,用于保存所有要通知的观察者对象,下面来介绍它最重要的 3 个方法。
    void addObserver(Observer o) 方法:用于将新的观察者对象添加到向量中。
    void notifyObservers(Object arg) 方法:调用向量中的所有观察者对象的 update() 方法,通知它们数据发生改变。通常越晚加入向量的观察者越先得到通知。
    void setChange() 方法:用来设置一个 boolean 类型的内部标志位,注明目标对象发生了变化。当它为真时,notifyObservers() 才会通知观察者。
  2. Observer 接口
    Observer 接口是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 void update(Observable o,Object arg) 方法,进行相应的工作。

5.5 参考

http://c.biancheng.net/view/1390.html

6 策略模式

定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
在这里插入图片描述

在这里插入图片描述

7 外观模式:

为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。将平台组件封装统一接口,屏蔽底层,组合。适合SDK 对外发布功能。

在这里插入图片描述

8 命令模式:

Client/IServer(C/S) 结构 ,两个模块,甚至服务级别之间交互调用的,对发起发屏蔽细节。将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。对请求排队或记录请求日志,以及支持可撤消的操作。 将请求封装成为对象,所以客户的所有操作,其实就是多个命令类的对象而已,即参数化了。

将请求封装成为对象,所以客户的所有操作,其实就是多个命令类的对象而已,即参数化了。

8.0 适用性

1.抽象出待执行的动作以参数化某对象。

2.在不同的时刻指定、排列和执行请求。

3.支持取消操作。

4.支持修改日志,这样当系统崩溃时,这些修改可以被重做一遍。

5.用构建在原语操作上的高层操作构造一个系统。

invoker不需要直接调用Reciver,甚至不知道哪个Receiver存在.

8.1参与者

1.Command
声明执行操作的接口。

2.ConcreteCommand
将一个接收者对象绑定于一个动作。
调用接收者相应的操作,以实现Execute。

3.Client
创建一个具体命令对象并设定它的接收者。编排功能

4.Invoker
要求该命令执行这个请求。

5.Receiver
知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。Receiver/接受者是命令模式中不可或缺的角色,接受者可以是任意类型,通常由子命令绑定消息接受者。如果仅仅将目光聚焦到Command类层次,命令模式就会与策略模式/行为参数化混淆。

8.2 类图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

8.3实现

8.4 与策略模式的区别

命令模式中,Invoker不知道Receiver的任何信息;策略模式中,Client知道并依赖IServer。这是一个前提。在此基础上,既然Invoker不知道Receiver的任何信息,那么有没有Receiver,对于Invoker来说也就无关紧要了。策略模式中,抽象方法的名字是与应用环境相关的;而命令模式中,Command封装到抽象方法的名字是普适的。

策略模式 把易于变化的行为分别封装起来,让它们之间可以互相替换, 让这些行为的变化独立于拥有这些行为的客户。
GoF《设计模式》中说道:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。该模式使得算法可独立于它们的客户变化。

Command命令模式是一种对象行为型模式,它主要解决的问题是:在软件构建过程中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”的问题。
GoF《设计模式》中说道:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

从这点看:

策略模式是通过不同的算法做同一件事情:例如排序

而命令模式则是通过不同的命令做不同的事情,常含有(关联)接收者。

目标不同!

命令模式是含有不同的命令(含有接收者的请求):做不同的事情;隐藏接收者执行细节。常见菜单事件,

而策略模式含有不同的算法,做相同的事情;

区别在于是否含有接收者。命令模式含有,策略模式不含有。命令模式中的命令可以单独运行。

打个比喻就是:命令模式等于菜单中的复制,移动,压缩等,而策略模式是其中一个菜单的例如复制到不同算法实现

**总结:**命令模式可以被抽象地视为一种策略模式。但是显然命令模式处理的是更为复杂的情况。或许我们

可以这么讲:策略模式聚焦的是对相同请求更换解决方案的灵活性;而命令模式聚焦的是对多请求变化的

封装以及对相同请求不同的请求形式解决方法的可复用性

与外观模式的区别

1.外观模式是结构型模型,命令模式是行为型模型。
2.外观模式关注类如何组合聚合来解耦,命令模式关注方法间的通信来解耦。
3.外观模式主要为了简化操作。封装内部,不符合开闭原则,新增需要修改外观类。命令模式主要为了发送方接收方解耦,符合开闭原则
4.控制粒度不一样。还是用遥控器来举例,命令模式像一个多按钮的遥控器,每个按钮是一个命令,调用方使用某些按钮进行开关操作,并且还支持等待执行的行为。命令模式能细粒度的控制每个按钮的执行顺序,执行是否撤回。而外观模式则是更像遥控器上只有一个按钮,而这一个按钮执行多个设定好顺序的开关操作。并且中间不能撤回。外观模式无法穿透外观类(或接口)去细粒度的控制内部的执行顺序或某些特殊的逻辑。
命令模式控制内部细节操作,外观模式控制整体操作

万能的适配目标

★Command模式:Invoker不知道应该依赖谁,因此将普适方法exe ()作为适配目标。Command模式是适配器模式的特例。

8.5 参考

https://blog.csdn.net/wei_chong_chong/article/details/51363736
https://www.cnblogs.com/ssslinppp/p/5555299.html

9工厂模式

大量的产品需要创建,并且这些产品具有共同的接口 。

9.1 简单工厂模式

**定义:**定义了一个创建对象的类,由这个类来封装实例化对象的行为。

举例:(我们举一个pizza工厂的例子)

pizza工厂一共生产三种类型的pizza:chesse,pepper,greak。通过工厂类(SimplePizzaFactory)实例化这三种类型的对象。类图如下:

img

public class SimplePizzaFactory {
    public Pizza CreatePizza(String ordertype) {
        Pizza pizza = null;
        if (ordertype.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (ordertype.equals("greek")) {
            pizza = new GreekPizza();
        } else if (ordertype.equals("pepper")) {
            pizza = new PepperPizza();
        }
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

客户端调用

public class SimpleFactoryTest {

    public static void main(String[] args) {
        SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();
        Pizza greek = simplePizzaFactory.CreatePizza("greek");
    }
}

简单工厂存在的问题与解决方法: 简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了开闭原则,所以,从设计角度考虑,有一定的问题,如何解决?我们可以定义一个创建对象的抽象方法并创建多个不同的工厂类实现该抽象方法,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。这种方法也就是我们接下来要说的工厂方法模式。

9.2 工厂方法模式

**定义:**定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类

举例:(我们依然举pizza工厂的例子,不过这个例子中,pizza产地有两个:伦敦和纽约)。添加了一个新的产地,如果用简单工厂模式的的话,我们要去修改工厂代码,并且会增加一堆的if else语句。而工厂方法模式克服了简单工厂要修改代码的缺点,它会直接创建两个工厂,纽约工厂和伦敦工厂。类图如下:

img

PizzaFactory中有个抽象的方法。一种pizza一种工厂去创建。

abstract Pizza createPizza();

客户端调用

public class FactoryMethodTest {
    public static void main(String[] args) {
        CheeseFactory cheese = new CheeseFactory();
        cheese.oderPizza();

        GreekFactory greekFactory = new GreekFactory();
        greekFactory.oderPizza();
    }
}

9.3 抽象工厂模式

可以新增产品和产品族。提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。**所以说抽象工厂就像工厂,而工厂方法则像是工厂的一种产品生产线。**因此,我们可以用抽象工厂模式创建工厂,而用工厂方法模式创建生产线。比如,我们可以使用抽象工厂模式创建伦敦工厂和纽约工厂,使用工厂方法实现cheese pizza和greak pizza的生产。类图如下:

img

9.4 三种工厂模式的使用选择

简单工厂 : 用来生产同一等级结构中的任意产品。(不支持拓展增加产品)

工厂方法 :用来生产同一等级结构中的固定产品。(支持拓展增加产品)

抽象工厂 :用来生产不同产品族的全部产品。(支持拓展增加产品;支持增加产品族)

**简单工厂的适用场合:**只有伦敦工厂(只有这一个等级),并且这个工厂只生产三种类型的pizza:chesse,pepper,greak(固定产品)。

工厂方法的适用场合:现在不光有伦敦工厂,还增设了纽约工厂(仍然是同一等级结构,但是支持了产品的拓展),这两个工厂依然只生产三种类型的pizza:chesse,pepper,greak(固定产品)。

**抽象工厂的适用场合:**不光增设了纽约工厂(仍然是同一等级结构,但是支持了产品的拓展),这两个工厂还增加了一种新的类型的pizza:chinese pizza(增加产品族)。

总结一下三种模式:

简单工厂模式就是建立一个实例化对象的类,在该类中对多个对象实例化。工厂方法模式是定义了一个创建对象的抽象方法,由子类决定要实例化的类。这样做的好处是再有新的类型的对象需要实例化只要增加子类即可。抽象工厂模式定义了一个接口用于创建对象族,而无需明确指定具体类。抽象工厂也是把对象的实例化交给了子类,即支持拓展。同时提供给客户端接口,避免了用户直接操作子类工厂。

11 链式职责(必考)

责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

**主要解决:**职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

**何时使用:**在处理消息的时候以过滤很多道。

**如何解决:**拦截的类都实现统一接口。

**关键代码:**Handler 里面聚合它自己,在 HanleRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。

应用实例: 1、红楼梦中的"击鼓传花"。 2、JS 中的事件冒泡。 3、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。

优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。

缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。

使用场景: 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、可动态指定一组对象处理请求。

11.1 参与者

(1)Handler:抽象处理者。它规范了每一个具体处理者的信息。

(2)ConcreteHandler:具体处理者。可以自己处理,也可以交给自己的下家处理。

(3)Client:客户端。向处理者提交请求对象。

11.2 类图

图片描述

在这里插入图片描述

11.3 实现

第一步:抽象处理者
public abstract class Handler {
    protected Handler successor;
    public abstract void handler(String  msg);
    public abstract void setSuccessor(Handler successor);
    public abstract Handler getSuccessor();
}
第二步:指定具体处理者

首先是士兵:

public class Soilder extends Handler{
	//指定消息处理继承人
	private Handler successor;
	@Override
	public void handler(String msg) {
		System.out.println("士兵没有权利处理,交给上司");
		this.successor.handler(msg);
	}
	@Override
	public void setSuccessor(Handler successor) {
		this.successor = successor;
	}
	@Override
	public Handler getSuccessor() {
		return successor;
	}
}
然后是大臣

public class Minister extends Handler{
	//指定消息处理继承人
	private Handler successor;
	@Override
	public void handler(String msg) {
		System.out.println("大臣也没有权利处理,交给皇帝");
		this.successor.handler(msg);
	}
	@Override
	public void setSuccessor(Handler successor) {
		this.successor = successor;
	}
	@Override
	public Handler getSuccessor() {
		return successor;
	}
}
最后是皇帝:

public class Emperor extends Handler{
	//指定消息处理继承人
	private Handler successor;
	@Override
	public void handler(String msg) {
		System.out.println("皇帝直接处理了");
		//注意在这里就不在指派其他人了
	}
	@Override
	public void setSuccessor(Handler successor) {
		this.successor = successor;
	}
	@Override
	public Handler getSuccessor() {
		return successor;
	}
}
这里我们可以发现,我们可以为每一个具体实现者设置下一任继承者,当然到达食物链最顶尖的那个可以不设置。

第三步:客户端调用

public class Client {
	public static void main(String[] args) {
		//这里的client就相当于前线将军
		String msg = "前线战况紧急,请求支援";
		Soilder soilder=new Soilder();
		Minister minister = new Minister();
		Emperor emperor = new Emperor();
		//为每一级别指定继承者
		soilder.setSuccessor(minister);
		minister.setSuccessor(emperor);
		//第一级别执行
		soilder.handler(msg);
	}
}

//输出
//士兵没有权利处理,交给上司
//大臣也没有权利处理,交给皇帝
//皇帝直接处理了

11.3 类图

12 模板方法模式

在这里插入图片描述

13 原型模式

使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。控制深浅拷贝。

在这里插入图片描述

14 操盘手模式

15 访问者模式

16 迭代器

17 状态模式

第二章 DUBBO使用的设计模式

1…责任链模式

责任链模式在Dubbo中发挥的作用举足轻重,就像是Dubbo框架的骨架。Dubbo的调用链组织是用责任链模式串连起来的。责任链中的每个节点实现Filter接口,然后由ProtocolFilterWrapper,将所有Filter串连起来。Dubbo的许多功能都是通过Filter扩展实现的,比如监控、日志、缓存、安全、telnet以及RPC本身都是。如果把Dubbo比作一列火车,责任链就像是火车的各车厢,每个车厢的功能不同。如果需要加入新的功能,增加车厢就可以了,非常容易扩展。

2.观察者模式

Dubbo中使用观察者模式最典型的例子是RegistryService。消费者在初始化的时候回调用subscribe方法,注册一个观察者,如果观察者引用的服务地址列表发生改变,就会通过NotifyListener通知消费者。此外,Dubbo的InvokerListenerExporterListener 也实现了观察者模式,只要实现该接口,并注册,就可以接收到consumer端调用refer和provider端调用export的通知。Dubbo的注册/订阅模型和观察者模式就是天生一对。

3 修饰器模式

Dubbo中还大量用到了修饰器模式。比如ProtocolFilterWrapper类是对Protocol类的修饰。在export和refer方法中,配合责任链模式,把Filter组装成责任链,实现对Protocol功能的修饰。其他还有ProtocolListenerWrapperListenerInvokerWrapperInvokerWrapper等。个人感觉,修饰器模式是一把双刃剑,一方面用它可以方便地扩展类的功能,而且对用户无感,但另一方面,过多地使用修饰器模式不利于理解,因为一个类可能经过层层修饰,最终的行为已经和原始行为偏离较大。

4工厂方法模式

CacheFactory的实现采用的是工厂方法模式。CacheFactory接口定义getCache方法,然后定义一个AbstractCacheFactory抽象类实现CacheFactory,并将实际创建cache的createCache方法分离出来,并设置为抽象方法。这样具体cache的创建工作就留给具体的子类去完成。

5 抽象工厂模式

ProxyFactory及其子类是Dubbo中使用抽象工厂模式的典型例子。ProxyFactory提供两个方法,分别用来生产ProxyInvoker(这两个方法签名看起来有些矛盾,因为getProxy方法需要传入一个Invoker对象,而getInvoker方法需要传入一个Proxy对象,看起来会形成循环依赖,但其实两个方式使用的场景不一样)。AbstractProxyFactory实现了ProxyFactory接口,作为具体实现类的抽象父类。然后定义了JdkProxyFactoryJavassistProxyFactory两个具体类,分别用来生产基于jdk代理机制和基于javassist代理机制的ProxyInvoker

6 适配器模式

为了让用户根据自己的需求选择日志组件,Dubbo自定义了自己的Logger接口,并为常见的日志组件(包括jcl, jdk, log4j, slf4j)提供相应的适配器。并且利用简单工厂模式提供一个LoggerFactory,客户可以创建抽象的Dubbo自定义Logger,而无需关心实际使用的日志组件类型。在LoggerFactory初始化时,客户通过设置系统变量的方式选择自己所用的日志组件,这样提供了很大的灵活性。

7 代理模式

Dubbo consumer使用Proxy类创建远程服务的本地代理,本地代理实现和远程服务一样的接口,并且屏蔽了网络通信的细节,使得用户在使用本地代理的时候,感觉和使用本地服务一样。

第三章Spring 框架中用到了哪些设计模式

工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
代理设计模式 : Spring AOP 功能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller

第四章 JDK 类库常用的设计模式有哪些?

答:JDK 常用的设计模式如下:

1)工厂模式

java.text.DateFormat 工具类,它用于格式化一个本地日期或者时间。

public final static DateFormat getDateInstance();
public final static DateFormat getDateInstance(int style);
public final static DateFormat getDateInstance(int style,Locale locale);

加密类

KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
Cipher cipher = Cipher.getInstance("DESede");
2)适配器模式

把其他类适配为集合类

List<Integer> arrayList = java.util.Arrays.asList(new Integer[]{1,2,3});
List<Integer> arrayList = java.util.Arrays.asList(1,2,3);
3)代理模式

如 JDK 本身的动态代理。

interface Animal {
    void eat();
}
class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("The dog is eating");
    }
}
class Cat implements Animal {
    @Override
    public void eat() {
        System.out.println("The cat is eating");
    }
}

// JDK 代理类
class AnimalProxy implements InvocationHandler {
    private Object target; // 代理对象
    public Object getInstance(Object target) {
        this.target = target;
        // 取得代理对象
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用前");
        Object result = method.invoke(target, args); // 方法调用
        System.out.println("调用后");
        return result;
    }
}

public static void main(String[] args) {
    // JDK 动态代理调用
    AnimalProxy proxy = new AnimalProxy();
    Animal dogProxy = (Animal) proxy.getInstance(new Dog());
    dogProxy.eat();
}
4)单例模式

全局只允许有一个实例,比如:

Runtime.getRuntime();
5)装饰器

为一个对象动态的加上一系列的动作,而不需要因为这些动作的不同而产生大量的继承类。

java.io.BufferedInputStream(InputStream);  
java.io.DataInputStream(InputStream);  
java.io.BufferedOutputStream(OutputStream);  
java.util.zip.ZipOutputStream(OutputStream);  
java.util.Collections.checkedList(List list, Class type) ;
6)模板方法模式

定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中。

比如,Arrays.sort() 方法,它要求对象实现 Comparable 接口。

class Person implements Comparable{
    private Integer age;
    public Person(Integer age){
        this.age = age;
    }
    @Override
    public int compareTo(Object o) {
        Person person = (Person)o;
        return this.age.compareTo(person.age);
    }
}
public class SortTest(){
    public static void main(String[] args){
        Person p1 = new Person(10);
        Person p2 = new Person(5);
        Person p3 = new Person(15);
        Person[] persons = {p1,p2,p3};
        //排序
        Arrays.sort(persons);
    }
}
12.IO 使用了什么设计模式?

答:IO 使用了适配器模式和装饰器模式。

  • 适配器模式:由于 InputStream 是字节流不能享受到字符流读取字符那么便捷的功能,借助 InputStreamReader 将其转为 Reader 子类,因而可以拥有便捷操作文本文件方法;
  • 装饰器模式:将 InputStream 字节流包装为其他流的过程就是装饰器模式,比如,包装为 FileInputStream、ByteArrayInputStream、PipedInputStream 等。

第五章 其他面试题

1.请列举出在 JDK 中几个常用的设计模式?
2.什么是设计模式?你是否在你的代码里面使用过任何设计模式?
3.Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
4.在 Java 中,什么叫观察者设计模式(observer design pattern)?
5.使用工厂模式最主要的好处是什么?在哪里使用?
6.举一个用 Java 实现的装饰模式(decorator design pattern)?它是作用于对象层次还是类
层次?
7.在 Java 中,为什么不允许从静态方法中访问非静态变量?
8.设计一个 ATM 机,请说出你的设计思路?
9.在 Java 中,什么时候用重载,什么时候用重写?
10.举例说明什么情况下会更倾向于使用抽象类而不是接口

6 visual-paradigm

https://online.visual-paradigm.com/cn/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值