<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>设计模式 on 分享技术带来的喜悦</title><link>https://bridgeli.cn/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/</link><description>Recent content in 设计模式 on 分享技术带来的喜悦</description><generator>Hugo -- 0.156.0</generator><language>zh-cn</language><lastBuildDate>Sun, 14 Dec 2014 15:33:31 +0000</lastBuildDate><atom:link href="https://bridgeli.cn/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/index.xml" rel="self" type="application/rss+xml"/><item><title>设计模式综合运用之Excel导入</title><link>https://bridgeli.cn/posts/2014-12-14-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%BB%BC%E5%90%88%E8%BF%90%E7%94%A8%E4%B9%8Bexcel%E5%AF%BC%E5%85%A5/</link><pubDate>Sun, 14 Dec 2014 15:33:31 +0000</pubDate><guid>https://bridgeli.cn/posts/2014-12-14-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%BB%BC%E5%90%88%E8%BF%90%E7%94%A8%E4%B9%8Bexcel%E5%AF%BC%E5%85%A5/</guid><description>&lt;p&gt;学以致用，前几篇文章我们学了很多设计模式，今天我们就把这些模式综合运用一下，看看实际应用是怎么导入Excel的，（当然这里面没有用到侦听者模式）&lt;br&gt;
我们先看一下Excel的样子：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.bridgeli.cn/wp-content/uploads/2014/12/20141214232827.png"&gt;&lt;img loading="lazy" decoding="async" src="https://www.bridgeli.cn/wp-content/uploads/2014/12/20141214232827-300x107.png" alt="20141214232827" width="300" height="107" class="alignnone size-medium wp-image-125" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;因为是Excel的的解析，所以应该是前台上传的，我们应该有一个Servlet来接收前台传过来的数据：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;package cn.bridgeli.demo.servlet;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.bridgeli.demo.servce.Container;
import cn.bridgeli.demo.servce.ExcelParseStrategy;
public class ExcelParseServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//真正的情况下应该由前台传过来的，这里是模拟就写死了
File file = new File(&amp;#34;D:/Excel.xls&amp;#34;);
String excelType = request.getParameter(&amp;#34;excelType&amp;#34;);
// 此处是策略模式，至于怎么实现，大家可以参考策略模式
Container container = new Container();
ExcelParseStrategy excelParseStrategy = container.getStrategy(excelType);
excelParseStrategy.parse(file);
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;下面看ExcelParseStrategy接口，和具体策略的实现：&lt;/p&gt;</description></item><item><title>设计模式之模板方法</title><link>https://bridgeli.cn/posts/2014-12-07-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E6%A8%A1%E6%9D%BF%E6%96%B9%E6%B3%95/</link><pubDate>Sun, 07 Dec 2014 14:29:26 +0000</pubDate><guid>https://bridgeli.cn/posts/2014-12-07-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E6%A8%A1%E6%9D%BF%E6%96%B9%E6%B3%95/</guid><description>&lt;p&gt;这一节记录一下模板方法，在学模板方法之前，要先学习一下什么是模板，模板其实就是一个例子，例如我们做市场调研时，调研人员会给我们一个表格，我们只需要回答一些答案即可，映射到我们的代码中就是这个样子：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;aaaaaaaa
bbbbbbbb
cccccccc
\***\*****
dddddddd
eeeeeeee
########
ffffffff
gggggggg
$$$$$$$$
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这是我们第一次写的代码，但是我们在后来的coding中发现，这一段代码我们需要copy一份，只需要该其中的第四行、第七行、第十行就行了，其余的不需要做修改，如果我们copy过去，改一下这么做虽然可以完成，但我们想一想如果我们代码里面一万处这样的代码，难道要copy一万次？这么做是不是很冗余？这时候就需要我们的模板方法上场了，下面看一个我们在实际中的典型应用：JDBC操作数据库，所以我们下面先看一个操作数据库的实际例子：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;package cn.bridgeli.demo.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import cn.bridgeli.demo.entity.User;
import cn.bridgeli.demo.util.DBUtil;
public class UserDao {
public User getUserById(int userId) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
User user = null;
String sql = &amp;#34;SELECT * FROM user WHERE id = ?&amp;#34;;
try {
conn = DBUtil.getConn();
pstmt = DBUtil.getPstmt(conn, sql);
pstmt.setInt(1, userId);
rs = pstmt.executeQuery();
if (rs.next()) {
user = new User();
//
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(rs);
DBUtil.close(pstmt);
DBUtil.close(conn);
}
return user;
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这段代码经过我们分析，很明显就建行不一样：String SQL不一样，pStmt设置参数不一样，if（rs.next()）不一样，所以我们可以把它做成模板方法，下面我们就重构着一段代码。在重构这段代码之前有几个问题我们先要明确：&lt;/p&gt;</description></item><item><title>设计模式之策略模式</title><link>https://bridgeli.cn/posts/2014-11-30-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/</link><pubDate>Sun, 30 Nov 2014 14:14:44 +0000</pubDate><guid>https://bridgeli.cn/posts/2014-11-30-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F/</guid><description>&lt;p&gt;今天我们来讨论策略模式，策略模式是一个比较难理解的模式，尤其是和工厂模式相结合时，当时看程杰的《大化设计模式》时，第二个讲的就是这个，那是一个迷迷糊糊啊，其实仔细分析策略模式并没有那么难，在我们学策略模式之前，先搞明白什么是策略呢？策略是：在某一件事上，在一定的情况下，所采取的行动。当然这个“在一定的情况下”一定是某一种情况，也即是可数的。当情况很多的时候，也许我们要用很多烦人if-else去处理，所以策略模式就是解决这类问题的，其一个典型应用就是在电商平台中：不同的用户有不同的等级享有不同的折扣，我想有些人第一想到的处理方式就是：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;package cn.bridgeli.demo;
public class Strategy {
public double discount(String grade, double total) {
if (&amp;#34;A&amp;#34;.equals(grade)) {
return total * 0.6;
} else if (&amp;#34;B&amp;#34;.equals(grade)) {
return total * 0.7;
} else if (&amp;#34;C&amp;#34;.equals(grade)) {
return total * 0.8;
} else if (&amp;#34;D&amp;#34;.equals(grade)) {
return total * 0.9;
} else {
return total;
}
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我相信这么处理只要看过上篇文章的人都会想到，不满足：开闭原则！当我们新增一个策略时，肯定要该这段代码，增加一个if，当我们的策略发生变化时，例如不仅打折而且在过节时发送促销邮件之类的，那么里面的策略也要改，显然这是一个大问题，那么出现这个问题的根源就是不满足：迪米特原则。&lt;br&gt;
ps：就算不用if-else，用switch-case也有同样的问题。那么用策略模式怎么处理呢？&lt;br&gt;
需要我们首先定义一个策略模式的接口：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;package cn.bridgeli.demo.service;
public interface UserGradeStrategyService {
public double discount();
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;下面是具体的策略的实现&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
package cn.bridgeli.demo.service;
public class UserGradeAStrategyService implements UserGradeStrategyService {
@Override
public double discount() {
return 0.6;
}
}
package cn.bridgeli.demo.service;
public class UserGradeBStrategyService implements UserGradeStrategyService {
@Override
public double discount() {
return 0.7;
}
}
package cn.bridgeli.demo.service;
public class UserGradeCStrategyService implements UserGradeStrategyService {
@Override
public double discount() {
return 0.8;
}
}
package cn.bridgeli.demo.service;
public class UserGradeDStrategyService implements UserGradeStrategyService {
@Override
public double discount() {
return 0.9;
}
}
package cn.bridgeli.demo.service;
public class UserGradeEStrategyService implements UserGradeStrategyService {
@Override
public double discount() {
return 1.0;
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;有一个策略的容器，这个容器知道都有哪些策略，它里面包含所有的策略：&lt;/p&gt;</description></item><item><title>设计模式之侦听者模式</title><link>https://bridgeli.cn/posts/2014-11-23-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E4%BE%A6%E5%90%AC%E8%80%85%E6%A8%A1%E5%BC%8F/</link><pubDate>Sun, 23 Nov 2014 10:41:16 +0000</pubDate><guid>https://bridgeli.cn/posts/2014-11-23-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E4%BE%A6%E5%90%AC%E8%80%85%E6%A8%A1%E5%BC%8F/</guid><description>&lt;p&gt;关于技术，老夫一直认为应该以实用为主，至于那些理论性的东西，用得多了慢慢就理解了，所以为了说明今天这个设计模式，我们先提出一个问题：我们知道很多系统都有注册功能，有些呢，直接返回您已注册成功请直接登录，而有些注册则要求相对比较比较高，例如注册成功之后需要向用户填写的手机发送短信、Email发送邮件之类的，关于这个问题，大家立马想到的也许是这么来实现吧：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;package cn.bridgeli.regdemo.service;
public class UserService {
public void register(String username, String password) {
// 非空验证
// save到数据库
// 发送短信说,注册成功
// 发送邮件说,注册成功
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这是一个很中规中矩的写法，我们都知道面向对象有一个原则是：单一职责原则，也即是最小知识化原则，好像也称迪米特原则和不和陌生人说话，不管怎么说，就是一个类只管一个类型的东西，一个方法只干一件事，例如本例中的注册，那么应该只干注册一件事，至于什么发短信啊，发邮件啊，本质上来说和注册是没有关系的，所以我们可以把发短信，发邮件的方法提取出来，放到其他的地方，例如放到工具类里面，那么提取出来是不是就是最好的了呢？我们应该知道面向对象还有一个原则：开闭原则，这个原则是说，对扩展开放对修改关闭，也就是说，当我们需求发生变化的时候，不应该依赖于去修改源码，而是依赖于对源码的扩展，所以关于我们这个例子：假设有一天我们不需要发送短信了，或者需要有第三种通知用户的方式，您是否能做到不修改源码呢？肯定做不到吧，只有把调用发送短信的代码删了，或者在下面添加第三种通知方式，所以这么做肯定还是不够的，那么为了满足：开闭原则，我们就要引入今天的设计模式：侦听者模式，且看下面的例子：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;package cn.bridgeli.regdemo.service;
import cn.bridgeli.regdemo.listener.EventLinstener;
public class UserService {
public void register(String username, String password) {
// 非空验证
// save到数据库
EventLinstener eventLinstener = new EventLinstener();
String data = &amp;#34;注册成功&amp;#34;;
eventLinstener.dispatchEvent(&amp;#34;REGSUCESSED&amp;#34;, data);
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;核心类EventLinstener&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;package cn.bridgeli.regdemo.listener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EventLinstener {
public static Map&amp;lt;String, List&amp;lt;Observer&amp;gt;&amp;gt; events = new HashMap&amp;lt;String, List&amp;lt;Observer&amp;gt;&amp;gt;();
static {
List&amp;lt;Observer&amp;gt; reg = new ArrayList&amp;lt;Observer&amp;gt;();
reg.add(new EmailObserver());
reg.add(new SmsObserver());
events.put(&amp;#34;REGSUCESSED&amp;#34;, reg);
}
public void dispatchEvent(String eventName, Object object) {
List&amp;lt;Observer&amp;gt; observers = events.get(eventName);
if (null != object &amp;amp;&amp;amp; !observers.isEmpty()) {
for (Observer observer : observers) {
observer.execute(object);
}
}
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;侦听者抽象类Observer&lt;/p&gt;</description></item><item><title>设计模式之单例模式</title><link>https://bridgeli.cn/posts/2014-11-16-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/</link><pubDate>Sun, 16 Nov 2014 12:42:05 +0000</pubDate><guid>https://bridgeli.cn/posts/2014-11-16-%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B9%8B%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/</guid><description>&lt;p&gt;在程序设计中，单例模式是非常常用的一个设计模式，至于有点老夫就不用多说了，肯定有一点比较省内存，但什么的类适合于设置成单例呢？一言以蔽之：&lt;/p&gt;
&lt;p&gt;在程序设计中，无状态的类都可以设置成单例。&lt;/p&gt;
&lt;p&gt;那么问题来了，什么样的类是无状态的，什么样的类是有状态的呢？其实很简单：&lt;/p&gt;
&lt;p&gt;没有数据，也就是说这个类只有方法，没有成员变量。&lt;/p&gt;
&lt;p&gt;举个例子：&lt;br&gt;
User类是否可以设置成单例呢？肯定不行，因为User类每一个对应的Id肯定是不同的人，如果设置成单例，数据就乱了；但一般Service层、DAO层的方法呢？这个一般都是一些业务逻辑，只有一些方法，没有数据，所以肯定可以设置成单例，事实上我们这些类如果有Spring托管，那么自然而然这些类就是单例的。&lt;/p&gt;
&lt;p&gt;既然单例使用这么多，有点还这么明显，那么怎么设置一个类是单例的呢？根据老夫第一个项目经理Zack的说法，设置一个类成单例的，有两种方法，首先看第一个，传统意义上的单例：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
package cn.bridgeli.singleton;
public class Singleton {
private static volatile Singleton singleton = null;
private Singleton() {
}
public static Singleton getInstance() {
if (null == singleton) {
synchronized (Singleton.class) {
if(null == singleton) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这个最简单，构造方法设置成私有的，别人就不能new了，想获取实例必须通过getInstance（）方法，而这个方法里面是static的，所以这是一个传统意义上的最简单的单例。&lt;/p&gt;
&lt;p&gt;除此之外，我们还可以借助于静态内部类的方式实现单利：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
package cn.bridgeli.demo.singleton;
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;第二个，管理意义上的单例&lt;br&gt;
我们自己观察可以发现，这个虽然简单，但我们Spring实现的单例，肯定不是这么实现的，那么他是怎么实现的呢？Spring并没有限制我们自己写的类必须要有一个私有的构造方法，所以管理意义上的单例，并不要一个类有一个私有的构造方法，但他会通过一个BeanFactory产生我们想要的实例，参考代码如下：&lt;/p&gt;</description></item></channel></rss>