![](http://upload-images.jianshu.io/upload_images/15083002-faad3732dd897756.jpg?imageMogr2/auto-orient/strip|imageView2/2/w/600/format/webp)
最易懂设计模式解析
适配器设计模式
Mybatis代理设计模式
Mybatis多级代理
1. 认识模板方法模式
1.1 模式定义
定义一个操作算法中的框架,而将这些步骤延迟加载到子类中。
它的本质就是固定算法框架。
1.2 解决何种问题
让父类控制子类方法的调用顺序
模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
1.3 模式好处
开发人员在开发时,只需要考虑方法的实现。不需要考虑方法在何种情况下被调用。实现代码复用。
1.4 模式适合场景
- 一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
- 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
- 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。
2. 模式结构与实例讲解
2.1模式结构
![](http://upload-images.jianshu.io/upload_images/15083002-ca73e8041db96ac2.png?imageMogr2/auto-orient/strip|imageView2/2/w/542/format/webp)
如模板方法模式结构图所知,有两个类:
- AblstractClass(抽象类):在抽象类中定义了一系列的操作PrimitiveOperation,每个操作可以使具体的,也可以是抽象的,每个操作对应一个算法的步骤,在子类中可以重新定义或实现这些步骤。TmplateMethod()这个方法用于定义一个算法结构,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。
- ConcreteClass(具体子类):用于实现在父类中声明的抽象基本操作,也可以覆盖在父类中已经实现的具体基本操作。
2.2 实例讲解
创建一个抽象模板结构(AblstractClass)好父亲
public abstract class AblstractClass {
<span class="token comment">//模板方法用来控制子类的顺序 要想有人生必须按老爸的人生顺序来 </span> <span class="token comment">//声明final不让子类覆盖这个方法,防止改变人生顺序</span> <span class="token keyword">public</span> final <span class="token keyword">void</span> 人生<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> 学习<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 工作<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 爱情<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//家里穷更得用工学习</span> <span class="token keyword">public</span> <span class="token keyword">void</span> 学习<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> System<span class="token punctuation">.</span><span class="token keyword">out</span><span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"每天晚上趴在邻居窗上学习"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//工作必须稳定</span> <span class="token keyword">public</span> <span class="token keyword">void</span> 工作<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> System<span class="token punctuation">.</span><span class="token keyword">out</span><span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"从一而终"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//恋爱自由 让儿子自由恋去</span> <span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">void</span> 爱情<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
创建一个具体模板(ConcreteClass)好儿子
public class ConcreteClass extends AblstractClass {
<span class="token comment">//儿子不认可父亲的学习方法 考高分影响同学关系</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> 学习<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"60分万岁..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//父亲给我爱情自由 一定好好谈恋爱</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> 爱情<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"肤白貌美大长腿..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
调用他们的人生
public class TestMain {
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span> ConcreteClass cs <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token function">ConcreteClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> cs<span class="token punctuation">.</span>人生<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
结果输出
60分万岁...
从一而终
肤白貌美大长腿...
3. 模式在Servlet中的应用
3.1 自己实现一下
浏览器向服务端发送一个请求,常用请求方式有两种,get请求和post请求,这两种请求方式会导致请求参数在请求协议包(Http包)中的位置是不一样的,那么请求协议包中不同的内容到达服务端之后会有不同的对象进行处理,如请求头的内容由tomcat负责,请求体中的内容由request负责,所以此时,开发人员在拿到service()方法后考虑到它可以接受所有请求方式,因此会针对不同的请求方式封装不同的请求方法。
建一个OneServlet 继承GenericServlet,实现service()方法,需要重写里面的doPost和doGet方法。
public class OneServlet extends GenericServlet {
@<span class="token class-name">Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> req<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> arg1<span class="token punctuation">)</span> throws ServletException<span class="token punctuation">,</span> IOException <span class="token punctuation">{</span> <span class="token comment">//1.从协议包【请求行】中来读取浏览器发送的请求方式</span> <span class="token class-name">HttpServletRequest</span> request <span class="token operator">=</span> <span class="token punctuation">(</span>HttpServletRequest<span class="token punctuation">)</span>req<span class="token punctuation">;</span><span class="token comment">//一般来说由父类修饰的对象由子类来修饰对象,目的就是功能扩充</span> <span class="token class-name">String</span> method <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//POST GET</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token string">"GET"</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token function">doGet</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> arg1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token string">"POST"</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token function">doPost</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> arg1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">//处理浏览器发送的post请求</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doPost</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> arg0<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> arg1<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">//这里面是doPost封装好的方法</span> System<span class="token punctuation">.</span><span class="token keyword">out</span><span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"doPost is run...."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//处理浏览器发送的get请求</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doGet</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> arg0<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> arg1<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">//这里面是doPost封装好的方法</span> System<span class="token punctuation">.</span><span class="token keyword">out</span><span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"doGet is run...."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
现在开发人员面临的是,即需要做方法的实现,有需要考虑service()方法在何时调用。在实际开发过程中service()方法里面是一段重复性的代码,所有的servlet类实现中都需要写这么一段重复性的代码,这样重复的开发既增加工作量,又显得代码臃肿,降低了系统耦合度。模板方法设计模式就是来解决这个问题的。下面看一下怎么解决。
建立MyHttpServlet类(就是模板方法设计模式中的父类),继承GenericServlet类。
public class MyHttpServlet extends GenericServlet {
<span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> req<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> res<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span> <span class="token comment">//控制子类中的doGet和doPost方法</span> <span class="token comment">//1.从协议包【请求行】来读取浏览器发送的请求方式</span> <span class="token class-name">HttpServletRequest</span> request <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span><span class="token punctuation">)</span>req<span class="token punctuation">;</span> <span class="token class-name">String</span> method <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//POST GET</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token string">"GET"</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token function">doGet</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//this.doGet()</span> <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token string">"POST"</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>method<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token function">doPost</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doPost</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> arg0<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> arg1<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doGet</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> arg0<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> arg1<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token punctuation">}</span>
}
建立TwoServlet类,此时此刻开发人员不用去考虑何时调用doGet方法。当调用TwoServlet类的时候,tomcat一定是调用它的service()方法。
/** * Servlet implementation class TwoServlet */ public class TwoServlet extends MyHttpServlet {
<span class="token comment">//选择是接受doGet方法还是doPost方法</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doGet</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> arg0<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> arg1<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"ThreeServlet doGet is run..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
}
测试代码localhost:8080/.../...
ThreeServlet doGet is run...
3.2 看HttpServlet源码
HttpServlet也是继承了GenericServlet ,跟踪找到Service()方法,发现有两个service()方法。
//这个方法是从它的父类GenericServlet继承过来的 @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response;
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token punctuation">(</span>req <span class="token keyword">instanceof</span> <span class="token class-name">HttpServletRequest</span> <span class="token operator">&&</span> res <span class="token keyword">instanceof</span> <span class="token class-name">HttpServletResponse</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ServletException</span><span class="token punctuation">(</span><span class="token string">"non-HTTP request or response"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//分别对请求对象和响应对象做了类型强转。</span> request <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span><span class="token punctuation">)</span> req<span class="token punctuation">;</span> response <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">HttpServletResponse</span><span class="token punctuation">)</span> res<span class="token punctuation">;</span> <span class="token function">service</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> response<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//调用的是自己声明的service方法,重载。</span> <span class="token punctuation">}</span>
}
进入到自己声明的service()方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod();//读取请求方式
<span class="token keyword">if</span> <span class="token punctuation">(</span>method<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>METHOD_GET<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token comment">//根据请求方式调用对应方法</span> <span class="token keyword">long</span> lastModified <span class="token operator">=</span> <span class="token function">getLastModified</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>lastModified <span class="token operator">==</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// servlet doesn't support if-modified-since, no reason</span> <span class="token comment">// to go through further expensive logic</span> <span class="token function">doGet</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">long</span> ifModifiedSince <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getDateHeader</span><span class="token punctuation">(</span>HEADER_IFMODSINCE<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>ifModifiedSince <span class="token operator"><</span> lastModified<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// If the servlet mod time is later, call doGet()</span> <span class="token comment">// Round down to the nearest second for a proper compare</span> <span class="token comment">// A ifModifiedSince of -1 will always be less</span> <span class="token function">maybeSetLastModified</span><span class="token punctuation">(</span>resp<span class="token punctuation">,</span> lastModified<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">doGet</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> resp<span class="token punctuation">.</span><span class="token function">setStatus</span><span class="token punctuation">(</span>HttpServletResponse<span class="token punctuation">.</span>SC_NOT_MODIFIED<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>method<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>METHOD_HEAD<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">long</span> lastModified <span class="token operator">=</span> <span class="token function">getLastModified</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">maybeSetLastModified</span><span class="token punctuation">(</span>resp<span class="token punctuation">,</span> lastModified<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">doHead</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>method<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>METHOD_POST<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">doPost</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>method<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>METHOD_PUT<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">doPut</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>method<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>METHOD_DELETE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">doDelete</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>method<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>METHOD_OPTIONS<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">doOptions</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span>resp<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>method<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>METHOD_TRACE<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">doTrace</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span>resp<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token comment">//</span> <span class="token comment">// Note that this means NO servlet supports whatever</span> <span class="token comment">// method was requested, anywhere on this server.</span> <span class="token comment">//</span> <span class="token class-name">String</span> errMsg <span class="token operator">=</span> lStrings<span class="token punctuation">.</span><span class="token function">getString</span><span class="token punctuation">(</span><span class="token string">"http.method_not_implemented"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Object<span class="token punctuation">[</span><span class="token punctuation">]</span> errArgs <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> errArgs<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">=</span> method<span class="token punctuation">;</span> errMsg <span class="token operator">=</span> MessageFormat<span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span>errMsg<span class="token punctuation">,</span> errArgs<span class="token punctuation">)</span><span class="token punctuation">;</span> resp<span class="token punctuation">.</span><span class="token function">sendError</span><span class="token punctuation">(</span>HttpServletResponse<span class="token punctuation">.</span>SC_NOT_IMPLEMENTED<span class="token punctuation">,</span> errMsg<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
发现service方法没有使用final,这是因为如果使用final修饰,就彻底断绝了我们下游开发人员的开发,这样是降低了系统的灵活度。
设计模式是问题解决思想(办法),没有固定的命令搭配 。
如果我们自己可以有这样一些解决办法,那就是好的设计模式。