设计模式
13、享元模式的概念及Java实现
享元模式(Flyweight Pattern)主要通过对象的复用来减少对象创建的次数和数量,以减少系统内存的使用和降低系统的负载。享元模式属于结构型模式,在系统需要一个对象时享元模式首先在系统中查找并尝试重用现有的对象,如果未找到匹配的对象,则创建新对象并将其缓存在系统中以便下次使用。
享元模式主要用于避免在有大量对象时频繁创建和销毁对象造成系统资源的浪费,把其中共同的部分抽象出来,如果有相同的业务请求,则直接返回内存中已有的对象,避免重新创建。
下面以内存的申请和使用为例介绍享元模式的使用方法,创建一个MemoryFactory作为内存管理的工厂,用户通过工厂获取内存,在系统内存池有可用内存时直接获取该内存,如果没有则创建一个内存对象放入内存池,等下次有相同的内存请求过来时直接将该内存分配给用户即可。具体的UML设计如图所示。
具体实现如下。
(1)定义Memory:
public class Memory {
private int size; //内存大小,单位为MB
private boolean isused; //内存是否在被使用
private String id; //内存id
public Memory(int size, boolean isused, String id) {
this.size = size;
this.isused = isused;
this.id = id;
}
//getter setter方法省略
}
(2)定义MemoryFactory工厂:
public class MemoryFactory {
private final static Log logger = LogFactory.getLog(MemoryFactory.class);
//内存对象列表
private static List<Memory> memoryList = new ArrayList<Memory>();
public static Memory getMemory(int size){
Memory memory = null;
for (int i = 0 ; i<memoryList.size() ; i++) {
memory = memoryList.get(i);
//如果存在和需求size一样大小并且未使用的内存块,则直接返回
if(memory.getSize()==size && memory.isIsused() ==false){
memory.setIsused(true);
memoryList.set(i, memory);
logger.info("get memory form memoryList:"+
JSON.toJSONString(memory));
break;
}
}
//如果内存不存在,则从系统中申请新的内存返回,并将该内存加入内存对象列表中
if(memory == null ){
memory = new Memory(32, false, UUID.randomUUID().toString());
logger.info("create a new memory form system and add to
memoryList:"+ JSON.toJSONString(memory));
memoryList.add(memory);
}
return memory;
}
//释放内存
public static void releaseMemory(String id){
for (int i = 0 ; i<memoryList.size() ; i++) {
Memory memory = memoryList.get(i);
//如果存在和需求size一样大小并且未使用的内存块,则直接返回
if(memory.getId().equals(id)){
memory.setIsused(false);
memoryList.set(i, memory);
logger.info("release memory:"+ id);
break;
}
}
}
}
以上代码定义了工厂类MemoryFactory,在该类中定义了memoryList用于存储从系统中申请到的内存,该类定义了getMemory,用于从memoryList列表中获取内存,如果在内存中有空闲的内存,则直接取出来返回,并将该内存的使用状态设置为已使用,如果没有,则创建内存并放入内存列表;还定义了releaseMemory来释放内存,具体做法是将内存的使用状态设置为false。
(3)使用享元模式:
public static void main(String[] args) {
//首次获取内存,将创建一个内存
Memory memory = MemoryFactory.getMemory(32);
//在使用后释放内存
MemoryFactory.releaseMemory(memory.getId());
//重新获取内存
MemoryFactory.getMemory(32);
}
在使用享元模式时,直接从工厂类MemoryFactory中获取需要的数据Memory,在使用完成后释放即可,具体的运行结果如下:
[INFO] MemoryFactory - create a new memory form system and add to
memoryList:{"id":"c5cc6dca-cf26-41ec-8552-
2f744721a24b", "isused":false, "size":32}
[INFO] MemoryFactory - release memory:c5cc6dca-cf26-41ec-8552-2f744721a24b
[INFO] MemoryFactory - get memory form memoryList:{"id":"c5cc6dca-cf26-41ec-8552-2f744721a24b", "isused":true, "size":32}
14、策略模式的概念及Java实现
策略模式(Strategy Pattern)为同一个行为定义了不同的策略,并为每种策略都实现了不同的方法。在用户使用的时候,系统根据不同的策略自动切换不同的方法来实现策略的改变。同一个策略下的不同方法是对同一功能的不同实现,因此在使用时可以相互替换而不影响用户的使用。
策略模式的实现是在接口中定义不同的策略,在实现类中完成了对不同策略下具体行为的实现,并将用户的策略状态存储在上下文(Context)中来完成策略的存储和状态的改变。
我们在现实生活中常常碰到实现目标有多种可选策略的情况,比如下班后可以通过开车、坐公交、坐地铁、骑自行回家,在旅行时可以选择火车、飞机、汽车等交通工具,在淘宝上购买指定商品时可以选择直接减免部分钱、送赠品、送积分等方式。
对于上述情况,使用多重if …else条件转移语句也可实现,但属于硬编码方式,这样做不但会使代码复杂、难懂,而且在增加、删除、更换算法时都需要修改源代码,不易维护,违背了开闭原则。通过策略模式就能优雅地解决这些问题。
下面以旅游交通工具的选择为例实现策略模式,具体的UML设计如图所示。

具体实现如下。
(1)定义TravelStrategy:
public interface TravelStrategy {
void travelMode();
}
以上代码定义了策略模式接口TravelStrategy,并在该接口中定义了方法travelMode()来表示出行方式。
(2)定义TravelStrategy的两种实现方式TravelByAirStrategy和TravelByCarStrategy:
public class TravelByAirStrategy implements TravelStrategy{
private final static Log logger =
LogFactory.getLog(TravelByAirStrategy.class);
@Override
public void travelMode() {
logger.info("travel by air");
}
}
public class TravelByCarStrategy implements TravelStrategy{
private final static Log logger =
LogFactory.getLog(TravelByCarStrategy.class);
@Override
public void travelMode() {
logger.info("travel by car");
}
}
以上代码定义了TravelStrategy的两个实现类TravelByAirStrategy和TravelByCarStrategy,分别表示基于飞机的出行方式和基于开车自驾的出行方式,并实现了方法travelMode()。
(3)定义Context实现策略模式:
public class Context {
private TravelStrategy travelStrategy;
public TravelStrategy getTravelStrategy() {
return travelStrategy;
}
public void setTravelStrategy(TravelStrategy travelStrategy) {
this.travelStrategy = travelStrategy;
}
public void travelMode() {
this.travelStrategy.travelMode();
}
}
以上代码定义了策略模式实现的核心类Context,在该类中持有TravelStrategy实例并通过setTravelStrategy()实现了不同策略的切换。
(4)使用策略模式:
public static void main(String[] args) {
Context context = new Context();
TravelStrategy travelByAirStrategy = new TravelByAirStrategy();
//设置出行策略为飞机
context.setTravelStrategy(travelByAirStrategy);
context.travelMode();
logger.info("change TravelStrategy to travelByCarStrategy......");
//设置出行策略为开车自驾
TravelStrategy travelByCarStrategy= new TravelByCarStrategy();
context.setTravelStrategy(travelByCarStrategy);
context.travelMode();
}
在使用策略模式时,首先需要定义一个Context,然后定义不同的策略实现并将其注入Context中实现不同策略的切换。具体的执行结果如下:
[INFO] TravelByAirStrategy - travel by air
[INFO] StrategyDemo - change TravelStrategy to travelByCarStrategy......
[INFO] TravelByCarStrategy - travel by car
15、模板方法模式的概念及Java实现
模板方法(Template Method)模式定义了一个算法框架,并通过继承的方式将算法的实现延迟到子类中,使得子类可以在不改变算法框架及其流程的前提下重新定义该算法在某些特定环节的实现,是一种类行为型模式。
该模式在抽象类中定义了算法的结构并实现了公共部分算法,在子类中实现可变的部分并根据不同的业务需求实现不同的扩展。模板方法模式的优点在于其在父类(抽象类)中定义了算法的框架以保障算法的稳定性,同时在父类中实现了算法公共部分的方法来保障代码的复用;将部分算法部分延迟到子类中实现,因此子类可以通过继承的方式来扩展或重新定义算法的功能而不影响算法的稳定性,符合开闭原则。
模板方法模式需要注意抽象类与具体子类之间的协作,在具体使用时包含以下主要角色。
- 抽象类(Abstract Class):定义了算法的框架,由基本方法和模板方法组成。基本方法定义了算法有哪些环节,模板方法定义了算法各个环节执行的流程。
- 具体子类(Concrete Class):对在抽象类中定义的算法根据需求进行不同的实现。
下面以银行办理业务为例实现一个模板方法模式,我们去银行办理业务都要经过抽号、排队、办理业务和评价,其中的业务流程是固定的,但办理的具体业务比较多,比如取钱、存钱、开卡等。其中,办理业务的固定流程就是模板算法中的框架,它常常是不变的,由抽象类定义和实现,而具体办理的业务是可变的部分,通常交给子类去做具体的实现。具体的UML设计如图所示。

具体实现如下。
(1)定义AbstractTemplate模板类:
public abstract class AbstractTemplate {
private final static Log logger =
LogFactory.getLog(AbstractTemplate.class);
public void templateMethod(){ //模板方法,用于核心流程和算法的定义
checkNumber();
queueUp();
handleBusiness();
serviceEvaluation();
}
public void checkNumber(){ //1:抽号
logger.info("checkNumber......");
}
public void queueUp(){ //2:排队
logger.info("queue up......");
}
public abstract void handleBusiness(); //3:业务办理
public void serviceEvaluation() {//4:服务评价
logger.info("business finished, servic evaluation......");
}
}
以上代码定义了抽象类AbstractTemplate,用于实现模板方法模式,其中定义了checkNumber()表示抽号过程,queueUp()表示排队过程,handleBusiness()表示需要办理的具体业务,serviceEvaluation()表示在业务办理完成后对服务的评价,templateMethod()定义了银行办理业务的核心流程,即取号、排队、办理业务和评价。抽象类实现了取号、排队、办理业务这些公共方法,而将办理业务的具体方法交给具体的业务类实现。
(2)定义SaveMoney的业务实现:
public class SaveMoney extends AbstractTemplate {
private final static Log logger =
LogFactory.getLog(AbstractTemplate.class);
@Override
public void handleBusiness() {
logger.info("save money form bank.");
}
}
以上代码定义了SaveMoney并实现了handleBusiness(),以完成存钱的业务逻辑。
(3)定义TakeMoney的业务实现:
public class TakeMoney extends AbstractTemplate {
private final static Log logger =
LogFactory.getLog(AbstractTemplate.class);
@Override
public void handleBusiness() {
logger.info("take money form bank.");
}
}
以上代码定义了TakeMoney并实现了handleBusiness(),以完成取钱的业务逻辑。
(4)使用模板模式:
public static void main(String[] args) {
//办理取钱流程
AbstractTemplate template1 = new TakeMoney();
template1.templateMethod();
//办理存储流程
AbstractTemplate template2 = new SaveMoney();
template2.templateMethod();
}
在使用模板模式时只需按照需求定义具体的模板类实例并调用其模板方法即可,具体的执行结果如下:
[INFO] AbstractTemplate - checkNumber......
[INFO] AbstractTemplate - queue up......
[INFO] AbstractTemplate - take money form bank.
[INFO] AbstractTemplate - business finished, servic evaluation......
[INFO] AbstractTemplate - checkNumber......
[INFO] AbstractTemplate - queue up......
[INFO] AbstractTemplate - save money form bank.
[INFO] AbstractTemplate - business finished, servic evaluation......
16、观察者模式的概念及Java实现
观察者(Observer)模式指在被观察者的状态发生变化时,系统基于事件驱动理论将其状态通知到订阅其状态的观察者对象中,以完成状态的修改和事件传播。这种模式有时又叫作发布-订阅模式或者模型-视图模式。
观察者模式是一种对象行为型模式,观察者和被观察者之间的关系属于抽象耦合关系,主要优点是在观察者与被观察者之间建立了一套事件触发机制,以降低二者之间的耦合度。
观察者模式的主要角色如下。
- 抽象主题(Subject):持有订阅了该主题的观察者对象的集合,同时提供了增加、删除观察者对象的方法和主题状态发生变化后的通知方法。
- 具体主题(Concrete Subject):实现了抽象主题的通知方法,在主题的内部状态发生变化时,调用该方法通知订阅了主题状态的观察者对象。
- 抽象观察者(Observer):观察者的抽象类或接口,定义了主题状态发生变化时需要调用的方法。
- 具体观察者(Concrete Observer):抽象观察者的实现类,在收到主题状态变化的信息后执行具体的触发机制。
观察者模式具体的UML设计如图所示。

具体实现如下。
(1)定义抽象主题Subject:
//抽象目标类
public abstract class Subject {
protected List<Observer> observers=new ArrayList<Observer>();
//增加观察者
public void add(Observer observer) {
observers.add(observer);
}
//删除观察者
public void remove(Observer observer) {
observers.remove(observer);
}
public abstract void notifyObserver(String message); //通知观察者的抽象方法
}
以上代码定义了抽象主题Subject类,并定义和实现了方法add()、remove()来向Subject添加观察者和删除观察者,定义了抽象方法notifyObserver()来实现在消息发生变化时将变化后的消息发送给观察者。
(2)定义具体的主题ConcreteSubject:
public class ConcreteSubject extends Subject {
private final static Log logger =
LogFactory.getLog(ConcreteSubject.class);
public void notifyObserver(String message) {
for(Object obs:observers) {
logger.info("notify observer "+message+" change...");
((Observer)obs).dataChange(message);
}
}
}
以上代码定义了ConcreteSubject类,该类继承了Subject并实现了notifyObserver(),用于向观察者发送消息。
(3)定义抽象观察者Observer:
public interface Observer {
void dataChange(String message); //接收数据
}
以上代码定义了观察者Observer接口并定义了messageReceive(),用于接收ConcreteSubject发送的通知。
(4)定义具体的观察者ConcreteObserver:
public class ConcreteSubject extends Subject {
private final static Log logger =
LogFactory.getLog(ConcreteObserver.class);
public void dataChange(String message) {
logger.info("recive message:"+message);
}
}
以上代码定义了具体的观察者ConcreteObserver类,用于接收Observer发送过来的通知并做具体的消息处理。
(5)使用观察者模式:
public static void main(String[] args) {
Subject subject=new ConcreteSubject();
Observer obs=new ConcreteObserver();
subject.add(obs);
subject.notifyObserver("data1");
}
在使用观察者模式时首先要定义一个Subject主题,然后定义需要接收通知的观察者,接着将观察者加入主题的监控列表中,在有数据发生变化时,Subject(主题)会将变化后的消息发送给观察者,最后调用subject的方法notifyObserver()发送一个数据变化的通知,具体的运行结果如下:
[INFO] ConcreteSubject - notify observer data1 change...
[INFO] ConcreteObserver - recive message:data1
17、迭代器模式的概念及Java实现
迭代器(Iterator)模式提供了顺序访问集合对象中的各种元素,而不暴露该对象内部结构的方法。
Java中的集合就是典型的迭代器模式,比如HashMap,在我们需要遍历HashMap时,通过迭代器不停地获取Next元素就可以循环遍历集合中的所有元素。
迭代器模式将遍历集合中所有元素的操作封装成迭代器类,其目的是在不暴露集合对象内部结构的情况下,对外提供统一访问集合的内部数据的方法。迭代器的实现一般包括一个迭代器,用于执行具体的遍历操作;以及一个Collection,用于存储具体的数据。我们以Collection集合的迭代器设计为例介绍迭代器模式的设计思路。具体的UML设计如图所示。
具体实现如下。
(1)定义名为Collection的集合接口:
public interface Collection {
//对集合元素的迭代
public Iterator iterator();
//取得集合元素
public Object get(int i);
//向集合添加元素
public boolean add(Object object);
//取得集合大小
public int size();
}
以上代码定义了名为Collection的接口,用于制定集合操作的规范。在该接口中定义了iterator()用于集合接口的遍历,定义了get()用于获取集合中的元素,定义了add()用于向集合中添加元素,定义了size()用于获取集合的大小。
(2)定义Collection接口实现类ListCollection:
public class ListCollection implements Collection{
public List list = new ArrayList(); //list用于数据的存储
@Override
public Iterator iterator() {
return new ConcreteIterator(this);
}
@Override
public Object get(int i) {
return list.get(i);
}
@Override
public boolean add(Object object) {
list.add(object);
return true;
}
@Override
public int size() {
return list.size();
}
}
以上代码定义了Collection接口的实现类ListCollection,ListCollection类用于存储具体的数据并实现数据操作方法,其中,list用于存储数据,iterator()用于构造集合迭代器。
(3)定义迭代器接口Iterator:
public interface Iterator {
//指针前移
public Object previous();
//指针后移
public Object next();
public boolean hasNext();
}
以上代码定义了迭代器接口Iterator,在该接口中规范了迭代器应该实现的方法,其中,previous()用于访问迭代器中的上一个元素,next()用于访问迭代器中的下一个元素,hasNext()用于判断在迭代器中是否还有元素。
(4)定义迭代器接口Iterator的实现类ConcreteIterator:
public class ConcreteIterator implements Iterator {
private Collection collection;
private int pos = -1; //当前迭代器遍历到的元素位置
public ConcreteIterator(Collection collection){
this.collection = collection;
}
@Override
public Object previous() {
if(pos > 0){
pos--;
}
return collection.get(pos);
}
@Override
public Object next() {
if(pos<collection.size()-1){
pos++;
}
return collection.get(pos);
}
@Override
public boolean hasNext() {
if(pos<collection.size()-1){
return true;
}else{
return false;
}
}
}
以上代码定义了迭代器接口Iterator的实现类ConcreteIterator,在ConcreteIterator中定义了Collection用于访问集合中的数据,pos用于记录当前迭代器遍历到的元素位置,同时实现了在Iterator接口中定义的方法previous()、next()和hasNext(),以完成具体的迭代器需要实现的基础功能。
(5)使用迭代器:
public static void main(String[] args) {
//定义集合
Collection collection = new ListCollection();
//向集合中添加数据
collection.add("object1");
//使用迭代器遍历集合
Iterator it = collection.iterator();
while(it.hasNext()){
logger.info(it.next());
}
}
迭代器的使用方法比较简单:首先需要定义一个集合并向集合中加入数据,然后获取集合的Iterator迭代器并通过循环遍历集合中的数据。
18、责任链模式的概念及Java实现
责任链(Chain of Responsibility)模式也叫作职责链模式,用于避免请求发送者与多个请求处理者耦合在一起,让所有请求的处理者持有下一个对象的引用,从而将请求串联成一条链,在有请求发生时,可将请求沿着这条链传递,直到遇到该对象的处理器。
在责任链模式下,用户只需将请求发送到责任链上即可,无须关心请求的处理细节和传递过程,所以责任链模式优雅地将请求的发送和处理进行了解耦。
责任链模式在Web请求中很常见,比如我们要为客户端提供一个REST服务,服务端要针对客户端的请求实现用户鉴权、业务调用、结果反馈流程,就可以使用责任链模式实现。
责任链模式包含以下三种角色。
- Handler接口:用于规定在责任链上具体要执行的方法。
- AbstractHandler抽象类:持有Handler实例并通过setHandler()和getHandler()将各个具体的业务Handler串联成一个责任链,客户端上的请求在责任链上执行。
- 业务Handler:用户根据具体的业务需求实现的业务逻辑。
例如,用户鉴权、业务调用、结果反馈流程的责任链实现的具体UML设计如图所示。

具体实现如下。
(1)定义Handler接口:
public interface Handler {
void operator();
}
以上代码定义了Handler接口,该接口用于规定责任链上各个环节的操作,这里定义了operator(),用于在责任链上各个环节处理任务时进行调用。
(2)定义AbstractHandler类:
public abstract class AbstractHandler {
private Handler handler;
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
}
以上代码定义了抽象类AbstractHandler来将责任链上的各个组件连接起来,具体操作是通过setHandler()设置下一个环节的组件,通过getHandler()获取下一个环节的组件。
(3)定义用户授权类AuthHandler:
public class AuthHandler extends AbstractHandler implements Handler {
private final static Log logger = LogFactory.getLog(AuthHandler.class);
private String name;
public AuthHandler(String name) {
this.name = name;
}
@Override
public void operator() {
logger.info("user auth...");
if(getHandler()! =null){//执行责任链的下一个流程
getHandler().operator();
}
}
}
以上代码定义了用户授权类AuthHandler并实现了operator(),该方法首先调用当前环节的业务流程,即用户授权,然后通过getHandler()获取下一个组件并调用其operator(),使其执行下一个责任链流程。
(4)定义业务处理类BusinessHandler:
public class BusinessHandler extends AbstractHandler implements Handler {
private final static Log logger =
LogFactory.getLog(BusinessHandler.class);
private String name;
public BusinessHandler(String name) {
this.name = name;
}
@Override
public void operator() {
logger.info("business info handler...");
if(getHandler()! =null){//执行责任链的下一个流程
getHandler().operator();
}
}
}
以上代码定义了用户授权类BusinessHandler并实现了方法operator(),该方法首先调用当前环节的业务流程,即业务处理流程,然后通过getHandler()获取下一个组件并调用其operator(),使其执行责任链的下一个流程。
(5)定义请求反馈类ResponseHandler:
public class ResponseHandler extends AbstractHandler implements Handler {
private final static Log logger =
LogFactory.getLog(ResponseHandler.class);
private String name;
public ResponseHandler(String name) {
this.name = name;
}
@Override
public void operator() {
logger.info("message response...");
if(getHandler()! =null){//执行责任链的下一个流程
getHandler().operator();
}
}
}
以上代码定义了用户授权类ResponseHandler并实现了operator(),该方法首先调用当前环节的业务流程,这里的业务流程主要是判断业务流程执行的结果并做出相应的反馈,然后通过getHandler()获取下一个组件并调用其operator(),使其执行下一个责任链流程。
(6)使用责任链模式:
public static void main(String[] args) {
AuthHandler authHandler= new AuthHandler("auth");
BusinessHandler businessHandler= new BusinessHandler("business");
ResponseHandler responseHandler= new ResponseHandler("response");
authHandler.setHandler(businessHandler);
businessHandler.setHandler(responseHandler);
authHandler.operator();
}
在使用责任链模式时,首先要定义各个责任链的组件,然后将各个组件通过setHandler()串联起来,最后调用第一个责任链上的operator(),接着程序就像多米诺骨牌一样在责任链上执行下去。具体的执行结果如下:
[INFO] AuthHandler - user auth...
[INFO] BusinessHandler - business info handler...
[INFO] ResponseHandler - message response...
5360



被折叠的 条评论
为什么被折叠?



