redis致命错误的出现

#错误描述
我们将文件缓存到redis,但是在线上出现了一个问题,就是A企业群中发的文件,在B企业群中看文件时却看到了A企业群中的图片。

#经排查,结果如下:

##案例代码如下:

    import com.google.common.collect.Lists;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;

    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    import java.util.concurrent.*;

    /**
     * Created by Aaron on 15/11/12.
     */
    public class FileRedisFactory {
        private static Logger log = LoggerFactory.getLogger(FileRedisFactory.class);
        public ThreadPoolExecutor threadPoolExecutor;
        // 格式为 : 127.0.0.1:6379#0;127.0.0.2:6379#1    IP:PORT#index
        private String hosts;
        private String password;
        private int size;
        private List<JedisPool> pools=Lists.newArrayList();//连接池

        public FileRedisFactory(String hosts, String password) {
            this.hosts = hosts;
            this.password = password;
            this.init(hosts, password);
        }

        public FileRedisFactory(String hosts) {
            this.hosts = hosts;
            this.init(hosts, null);
        }


        private synchronized void init(String hosts, String password) {
            if (StringUtils.isNotEmpty(hosts)) {
                String[] hostsArray = hosts.split(";");
                List<String> hostList = Arrays.asList(hostsArray);
                Collections.sort(hostList);
                System.out.println(hostList);
                for (String host : hostList) {
                    try {
                        String[] uriDb=host.split("#");
                        String[] host_port = uriDb[0].split(":");
                        String ip = host_port[0];
                        String port = host_port[1];
                        int index=uriDb.length>0?Integer.valueOf(uriDb[1]):0;
                        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

                        poolConfig.setMaxTotal(16);
                        poolConfig.setMaxIdle(16);
                        if (StringUtils.isNotEmpty(password)) {
                            pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, password, index));
                        } else {
                            pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, null, index));
                        }
                    } catch (Exception e) {
                        pools = Lists.newArrayList();
                        e.printStackTrace();
                        log.error("[ShardedRedisFactory] [initByShard] [error] [hosts:" + hosts + "] [password:" + password + "]", e);
                    }
                }
                size = pools.size();
            }
            this.threadPoolExecutor = new ThreadPoolExecutor(10,20,3, TimeUnit.MINUTES,new LinkedBlockingDeque<>(),new ThreadPoolExecutor.DiscardPolicy());

            // 构造池
            log.info("[ShardedRedisFactory] [initByShard] [success] [hosts:{}] [password:{}] [masterName:{}] [pool:{}]", hosts, password);
        }

        private JedisPool getJedisPool(int c) {
            int index = c % size;
            return pools.get(index);
        }

        private static int getIndexFromPath(String path) {
            String first=path.split("\\.")[0];
            return  first.charAt(first.length() - 1);
        }

        /**
         * @param filePath file path
         * @return
         */
        public byte[] get(String filePath) {
            if (cacheIsAvailable()) return null;
            JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
            Jedis jedis = null;
            try {
                jedis = jedisPool.getResource();
                return jedis.get(filePath.getBytes());
            } catch (Exception e) {
                log.error(e.getMessage());
                return null;
            } finally {
                if (jedis != null)
                    jedisPool.returnResource(jedis);
            }
        }

        public void asynSet(String filePath, byte[] datas){
            if (cacheIsAvailable()) return;
            threadPoolExecutor.execute(()->{
                    JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
                    Jedis jedis = null;
                    try {
                        jedis = jedisPool.getResource();
                        jedis.set(filePath.getBytes(), datas);
                    } catch (Exception e) {
                        log.error(e.getMessage());
                    } finally {
                        if (jedis != null)
                            jedisPool.returnResource(jedis);
                    }
            });
        }
        private boolean cacheIsAvailable() {
            if(pools.size()==0){
                return true;
            }
            return false;
        }

    }

##测试代码如下

        public static void main(String[] args) {
            FileRedisFactory fileRedisFactory = new FileRedisFactory("172.31.xxx.xxx:6379#0;172.31.xx.xxx:6379#1;172.31.xxx.xxx:6379#2;172.31.xxx.xxx:6379#3");
            System.out.println(fileRedisFactory);
            Map<String,String> map=new HashMap<>();

            for(int i=0;i<20;i++){
                map.put(""+i,""+i);
            }

            for (int j = 0; j <50 ; j++) {
                Thread thread=new Thread(){
                    @Override
                    public void run() {
                        while(true){
                            Set<String> s=map.keySet();

                            s.forEach(i->{
                                fileRedisFactory.set(i + "", (i + "").getBytes());
                            });
                        }
                    }
                };
                thread.start();
            }
            for (int k = 0; k <50 ; k++) {
                Thread thread=new Thread(){
                    @Override
                    public void run() {
                        while(true){
                            Set<String> s=map.keySet();
                            s.forEach(i->{
                                byte[] first=fileRedisFactory.get(i+"");
                                if(first==null){
                                    System.out.println(i+""+first);
                                    return;
                                }
                                try{
                                String temp=(new String(first));
                                if(!temp.equals(i+"")){
                                    System.out.println(i+"======"+temp);
                                    System.exit(-1);
                                }}catch(Exception e){
                                    e.printStackTrace();
                                }
                            });
                        }
                    }
                };
                thread.start();
            }
        }

若你和连接到redis服务器之间的网络不是很稳定
在运行时,我们会发现,有奇怪的现像出现:

    1======2
    3======8

这时,我们就在对redis操作时,异常的地方修改成如下代码:

    catch (Exception e) {
          log.error(e.getMessage());
          e.printStackTrace();
          return null;
    } 

就会看到报TimeOut的Exception

我们将:
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.6.2</version>
        </dependency>

替换成:
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.3</version>
        </dependency>

这时我们去Google上查询的同时也看了一下新的代码,
我们原来用的:

    jedisPool.returnResource(jedis);

 已经变成了:


   /**
    * @deprecated starting from Jedis 3.0 this method won't exist. Resouce cleanup should be done
    *             using @see {@link redis.clients.jedis.Jedis#close()}
    */
   @Deprecated
   public void returnResource(final Jedis resource) {
     if (resource != null) {
       try {
         resource.resetState();
         returnResourceObject(resource);
       } catch (Exception e) {
         returnBrokenResource(resource);
         throw new JedisException("Could not return the resource to the pool", e);
       }
     }
   }

同时我们也查到了一个文章JedisPool异常Jedis链接处理

#修改后的代码:

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;

/**
 * Created by Aaron on 15/11/12.
 */
public class FileRedisFactory {
    private static Logger log = LoggerFactory.getLogger(FileRedisFactory.class);
    public ThreadPoolExecutor threadPoolExecutor;
    // 格式为 : 127.0.0.1:6379#0;127.0.0.2:6379#1    IP:PORT#index
    private String hosts;
    private String password;
    private int size;
    private List<JedisPool> pools=Lists.newArrayList();//连接池

    public FileRedisFactory(String hosts, String password) {
        this.hosts = hosts;
        this.password = password;
        this.init(hosts, password);
    }

    public FileRedisFactory(String hosts) {
        this.hosts = hosts;
        this.init(hosts, null);
    }


    private synchronized void init(String hosts, String password) {
        if (StringUtils.isNotEmpty(hosts)) {
            String[] hostsArray = hosts.split(";");
            List<String> hostList = Arrays.asList(hostsArray);
            Collections.sort(hostList);
            System.out.println(hostList);
            for (String host : hostList) {
                try {
                    String[] uriDb=host.split("#");
                    String[] host_port = uriDb[0].split(":");
                    String ip = host_port[0];
                    String port = host_port[1];
                    int index=uriDb.length>0?Integer.valueOf(uriDb[1]):0;
                    GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

                    poolConfig.setMaxTotal(16);
                    poolConfig.setMaxIdle(16);
                    if (StringUtils.isNotEmpty(password)) {
                        pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, password, index));
                    } else {
                        pools.add(new JedisPool(poolConfig, ip, Integer.valueOf(port), 2000, null, index));
                    }
                } catch (Exception e) {
                    pools = Lists.newArrayList();
                    log.error("[ShardedRedisFactory] [initByShard] [error] [hosts:" + hosts + "] [password:" + password + "]", e);
                }
            }
            size = pools.size();
        }

        this.threadPoolExecutor = new ThreadPoolExecutor(10,20,3, TimeUnit.MINUTES,new LinkedBlockingDeque<>(50),new ThreadPoolExecutor.DiscardPolicy());

        // 构造池
        log.info("[ShardedRedisFactory] [initByShard] [success] [hosts:{}] [password:{}] [masterName:{}] [pool:{}]", hosts, password);
    }

    private JedisPool getJedisPool(int c) {
        int index = c % size;
        return pools.get(index);
    }

    private static int getIndexFromPath(String path) {
        String first=path.split("\\.")[0];
        return  first.charAt(first.length() - 1);
    }

    /**
     * @param filePath file path
     * @return
     */
    public byte[] get(String filePath) {
        if (cacheIsAvailable()) return null;
        JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.get(filePath.getBytes());
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            if (jedis != null)
                jedis.close();
        }
    }

    public String set(String filePath, byte[] datas) {
        if (cacheIsAvailable()) return null;
        JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.set(filePath.getBytes(), datas);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        } finally {
            if (jedis != null)
                jedis.close();
        }
    }

    public void asynSet(String filePath, byte[] datas,long expx){
        if (cacheIsAvailable()) return;
        threadPoolExecutor.execute(()->{
                JedisPool jedisPool = getJedisPool(getIndexFromPath(filePath));
                Jedis jedis = null;
                try {
                    jedis = jedisPool.getResource();
                    jedis.set(filePath.getBytes(), datas,"NX".getBytes(),"EX".getBytes(),expx);
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    if (jedis != null)
                        jedis.close();
                }
        });
    }
    private boolean cacheIsAvailable() {
        if(pools.size()==0){
            return true;
        }
        return false;
    }

}

#总结:

  1. 在使用做新功能时,方便时要添加开关或合理的回滚方案,方便快速的回滚减少事故的影响
  2. 排查错误,一查到底

JMeter

##JMeter是用来做什么的

是一个Apache的一个开源程序,一个100%的针对压力模块和功能压力测试纯Java应用,最初是专门为Web应用程序而设计 的,但是目前已经扩展到别的功能 测试。

  • 能做什么?

    用来测试动态 和 静态资源(Webservices(SOAP/REST),Web dynamic languages -PHP,JAva,ASP.NET,Files,etc.Jav)

##如何本地进行服务压力测试

  • 在lib下建一个文件夹,如tests,将所有自己用到的jar,放到这个文件夹中。

  • 将自己的测试jar放到 lib/ext下面

  • 将自己的程序依赖的jar文件夹,配置到配置文件
    user.classpath=../lib/tests

##如何分发到不同的机器进行压力测试

参考官方文档http://jmeter.apache.org/usermanual/jmeter_distributed_testing_step_by_step.pdf

##聚合分析

Label:每个 JMeter 的 element(例如 HTTP Request)都有一个 Name 属性,这里显示的就是 Name 属性的值

#Samples:表示你这次测试中一共发出了多少个请求,如果模拟10个用户,每个用户迭代10次,那么这里显示100

Average:平均响应时间——默认情况下是单个 Request 的平均响应时间,当使用了 Transaction Controller 时,也可以以Transaction 为单位显示平均响应时间

Median:中位数,也就是 50% 用户的响应时间

90% Line:90% 用户的响应时间

Note:关于 50% 和 90% 并发用户数的含义,请参考下文

http://www.cnblogs.com/jackei/archive/2006/11/11/557972.html

Min:最小响应时间

Max:最大响应时间

Error%:本次测试中出现错误的请求的数量/请求的总数

Throughput:吞吐量——默认情况下表示每秒完成的请求数(Request per Second),当使用了 Transaction Controller 时,也可以表示类似 LoadRunner 的 Transaction per Second 数

KB/Sec:每秒从服务器端接收到的数据量,相当于LoadRunner中的Throughput/Sec

###问题

####Jmeter-server启动失败:Cannot start. Unable to get local host IP address. is a loopback address

    在Windows下启动Jmeter非常顺利,转到Linux下居然启动失败。
    想起之前 遇到“/etc/hosts文件设置不对导致Jboss启动失败”, 立马把焦点指向/etc/hosts。

    果然还是这个问题,贴/etc/hosts示例:

    127.0.0.1       localhost.localdomain localhost
    10.20.10.31   higkoo.rdev.company.net higkoo

    执行命令`hostname`查看当前机器名如果当前机器名与/etc/hosts不一致 ,可手动先执行成一次`hostname yourhostname`或直接加到jmeter-server文件中(注意机器名中不要含域信息,譬如:myname.rdev.company.com。这样设置仍然启动失败)。

    由/etc/hosts文件导致启动失败的错误有:
    1
    Created remote object: UnicastServerRef [liveRef: [endpoint:[10.20.10.31:62090](local),objID:[2c639f6d:12794fca52a:-7fff, 712947915258586677]]]
    Server failed to start: java.rmi.RemoteException: Cannot start. higkoo is a loopback address.
    2
    Created remote object: UnicastServerRef [liveRef: [endpoint:[10.20.10.31:38796](local),objID:[-b0d822e:12794fee8b1:-7fff, 8314597152635832475]]]
    Server failed to start: java.rmi.RemoteException: Cannot start. Unable to get local host IP address.

zookeeper学习及项目实践

ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. 。

它设计一种新的数据结构——Znode,然后在该数据结构的基础上定义了一些原语,也就是一些关于该数据结构的一些操作。有了这些数据结构和原语还不够,因为我们的ZooKeeper是工作在一个分布式的环境下,我们的服务是通过消息以网络的形式发送给我们的分布式应用程序,所以还需要一个通知机制——Watcher机制。那么总结一下,ZooKeeper所提供的服务主要是通过:数据结构+原语+watcher机制,三个部分来实现的。

使用场景下会使用zookeeper

  1. 项目中在监控mongodb的oplog来进行同步数据库的变更给别的部门.若想做的多机互备,就需要使用到分布式锁,由一台机器进行对oplog的变化进行同步
  2. 项目在定时发送提醒,多台服务器进行周期扫库操作,也同样用到了1中的分布式锁
  3. 假设我们有20个搜索引擎的服务器(每个负责总索引中的一部分的搜索任务)和一个总服务器(负责向这20个搜索引擎的服务器发出搜索请求并合并结果集),一个备用的总服务器(负责当总服务器宕机时替换总服务器),一个web的cgi(向总服务器发出搜索请求)。搜索引擎的服务器中的15个服务器提供搜索服务,5个服务器正在生成索引。这20个搜索引擎的服务器经常要让正在提供搜索服务的服务器停止提供服务开始生成索引,或生成索引的服务器已经把索引生成完成可以提供搜索服务了。使用Zookeeper可以保证总服务器自动感知有多少提供搜索引擎的服务器并向这些服务器发出搜索请求,当总服务器宕机时自动启用备用的总服务器.—分布式系统协调 ZooKeeper

zookeeper来源是什么?

ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务。由于ZooKeeper的开源特性,后来我们的开发者在分布式锁的基础上,摸索了出了其他的使用方法:配置维护、组服务、分布式消息队列、分布式通知/协调等。

协议

  1. 每个Server在内存中存储了一份数据;
  2. Zookeeper启动时,将从实例中选举一个leader(Leader选举算法采用了Paxos协议;Paxos核心思想:当多数Server写成功,则任务数据写成功。故 Server数目一般为奇数);
  3. Leader负责处理数据更新等操作(Zab协议);
  4. 一个更新操作成功,当且仅当大多数Server在内存中成功修改数据。

结构组成

  1. Leader 负责进行投票的发起和决议,更新系统状态
  2. Learner–>跟随者Follower 用于接收客户请求并向客户端返回结果,在选择中参与投票
  3. Learner–>观察者Observer 可以接收客户端连接,将写请求转发给Leader节点,但其不参悟投票过程,只同步Leader的状态.其目的是为了扩展系统,提高读取速度
  4. client 请求发起方

具体用在哪里

  1. 配置管理,一处修改,监听者进行更新
  2. 命名服务
  3. 分布式锁 即 Leader Election
  4. 集群管理
  5. 队列管理

Zookeeper文件系统

每个子目录项如 NameService 都被称作为znode,和文件系统一样,我们能够自由的增加、删除znode,在一个znode下增加、删除子znode,唯一的不同在于znode是可以存储数据的。
有四种类型的znode:

  1. PERSISTENT-持久化目录节点:客户端与zookeeper断开连接后,该节点依旧存在
  2. PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号
  3. EPHEMERAL-临时目录节点:客户端与zookeeper断开连接后,该节点被删除
  4. EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点:客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号

Zookeeper的特点

  1. 最终一致性:为客户端展示同一视图,这是zookeeper最重要的功能。
  2. 可靠性:如果消息被到一台服务器接受,那么它将被所有的服务器接受。
  3. 实时性:Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。
  4. 等待无关(wait-free):慢的或者失效的client不干预快速的client的请求。
  5. 原子性:更新只能成功或者失败,没有中间状态。
  6. 顺序性:所有Server,同一消息发布顺序一致。

场景分析

  1. 分布式锁的场景使用
zkCli.sh -server x.x.x.x:4180

ls /key

>[data, leader]

[zk: x.x.x.x:4180(CONNECTED) 6] get /key/leader

cZxid = 0xc1098cd0b0
ctime = Sun Jul 16 13:10:01 CST 2017
mZxid = 0xc1098cd0b0
mtime = Sun Jul 16 13:10:01 CST 2017
pZxid = 0xc112aec1c0
cversion = 152
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 2

[zk: x.x.x.x:4180(CONNECTED) 7] ls /key/leader
[_c_7ea9234d-3973-4e1d-8a6a-e2e30062cdc4-latch-0000000076, _c_5444e12a-c7ef-48bb-8ee6-271eea4a1c29-latch-0000000075]
[zk: x.x.x.x:4180(CONNECTED) 8] get /key/leader/_c_7ea9234d-3973-4e1d-8a6a-e2e30062cdc4-latch-0000000076
24
cZxid = 0xc112aec1c0
ctime = Fri Mar 30 16:58:50 CST 2018
mZxid = 0xc112aec1c0
mtime = Fri Mar 30 16:58:50 CST 2018
pZxid = 0xc112aec1c0
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0xd5848ddc5ec71f6
dataLength = 2
numChildren = 0

[zk: x.x.x.x:4180(CONNECTED) 9] get /key/leader/_c_5444e12a-c7ef-48bb-8ee6-271eea4a1c29-latch-0000000075
5
cZxid = 0xc1123e0f90
ctime = Tue Mar 27 10:55:03 CST 2018
mZxid = 0xc1123e0f90
mtime = Tue Mar 27 10:55:03 CST 2018
pZxid = 0xc1123e0f90
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x259977a5b1b3de0
dataLength = 1
numChildren = 0


经典文章链接

zookeeper系列
Leader选举
基本概念

Protobuf是什么

欢迎来到protocol buffer的开发者指南文档,一种语言无关、平台无关、扩展性好的用于通信协议、数据存储的结构化数据串行化方法。本文档面向希望使用protocol buffer的Java、C++或Python开发者。这个概览介绍了protocol buffer,并告诉你如何开始,你随后可以跟随编程指导深入了解protocol buffer编码方式API参考文档同样也是提供了这三种编程语言的版本,不够协议语言样式指导都是编写 .proto 文件。

什么是protocol buffer

ProtocolBuffer是用于结构化数据串行化的灵活、高效、自动的方法,有如XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。

他们如何工作

你首先需要在一个 .proto 文件中定义你需要做串行化的数据结构信息。每个ProtocolBuffer信息是一小段逻辑记录,包含一系列的键值对。这里有个非常简单的 .proto 文件定义了个人信息:


message Person {
required string name=1;
required int32 id=2;
optional string email=3;

enum PhoneType {
MOBILE=0;
HOME=1;
WORK=2;
}

message PhoneNumber {
required string number=1;
optional PhoneType type=2 [default=HOME];
}

repeated PhoneNumber phone=4;
}

有如你所见,消息格式很简单,每个消息类型拥有一个或多个特定的数字字段,每个字段拥有一个名字和一个值类型。值类型可以是数字(整数或浮点)、布尔型、字符串、原始字节或者其他ProtocolBuffer类型,还允许数据结构的分级。你可以指定可选字段,必选字段和重复字段。你可以在proto.html找到更多关于如何编写 .proto 文件的信息。

一旦你定义了自己的报文格式(message),你就可以运行ProtocolBuffer编译器,将你的 .proto 文件编译成特定语言的类。

为什么不用XML?

ProtocolBuffer拥有多项比XML更高级的串行化结构数据的特性,ProtocolBuffer:

    更简单
    小3-10倍
    快20-100倍
    更少的歧义
    可以方便的生成数据存取类 

例如,让我们看看如何在XML中建模Person的name和email字段:


<person>
<name>John Doe</name>
<email>jdoe@example.com</email>
</person>

对应的ProtocolBuffer报文则如下:

ProtocolBuffer的文本表示
这不是正常时使用的二进制数据

person {
name: "John Doe"
email: "jdoe@example.com"
}

当这个报文编码到ProtocolBuffer的二进制格式时(上面的文本仅用于调试和编辑),它只需要28字节和100-200ns的解析时间。而XML的版本需要69字节(除去空白)和 5000-10000ns的解析时间。

设计模式之创建型模式

##创建型模式
这六个模式都是与创建对象相关的

  • 简单工厂模式(Simple Factory);
  • 工厂方法模式(Factory Method);
  • 抽象工厂模式(Abstract Factory);
  • 创建者模式(Builder);
  • 原型模式(Prototype);
  • 单例模式(Singleton);

简单工厂模式(Simple Factory);

工厂方法模式(Factory Method);

建立一个工厂类,对实现同一接口的类进行实例化创建。

``
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public interface IParser {
String parse(Object obj);
}
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public class JSONParser implements IParser{
@Override
public String parse(Object obj) {
//create json string
return "{class:"+obj.getClass()+"}";
}
}
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public class XMLParser implements IParser{
@Override
public String parse(Object obj) {
//create xml string....
return "<object><class>"+obj.getClass()+"</class></object>";
}
}
package design.pattern.factory;

/**
* Created by Aaron on 15/9/13.
*/
public class ParserFactory {
public static final String TYPE_XML="xml";
public static final String TYPE_JSON="json";
public static IParser buildParser(String type){
switch (type){
case ParserFactory.TYPE_XML:return new XMLParser();
case ParserFactory.TYPE_JSON:return new JSONParser();
}
return null;
}

public static void main(String[] args){
IParser parser= ParserFactory.buildParser(ParserFactory.TYPE_JSON);
System.out.print(parser.parse(parser));
}
}

//output {class:JSONParser}

抽象工厂模式(Abstract Factory);

工厂方法,每创建一个新的类时,就要个性类工厂类,这样拓展性比较差,如何能通过不个性工厂类而进行扩展呢。这里就用到了抽象工厂模式,就是创建多个工厂,一旦要增加新的类型就增加一个新的工厂,不需要修改现有代码。

基于上面代码将ParserFactory工厂类用一个抽象工厂类和两个子工厂类进行代替
package design.pattern.abstractfactory;

import design.pattern.factory.*;

/**
* Created by Aaron on 15/9/13.
*/
public abstract class AbstractParserFactory {
abstract IParser create();
}

package design.pattern.abstractfactory;

/**
* Created by Aaron on 15/9/13.
*/
public class JSONParserFactory extends AbstractParserFactory {
@Override
IParser create() {
return new JSONParser();
}
}

package design.pattern.abstractfactory;

/**
* Created by Aaron on 15/9/13.
*/
public class XMLParserFactory extends AbstractParserFactory {
@Override
IParser create() {
return new XMLParser();
}
}

建造者模式(Builder);

GoF这样定义:

建造者模式:是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

咱们这里以创建应用为例,这里我们创建两个应用,考试系统和CRM系统,创建过程是,需求->原型图->开发计划->表设计->架构设计->功能实现->测试->交付 大概是这样一个简单的过程,这里就会看到同样的构建过程得到不同的表示。
package design.pattern.builder;

import java.util.Vector;

/**
* Created by Aaron on 15/9/13.
*/
public class Project {

private Vector<String> impleProcess=new Vector<String>();
public void process(String imple){
impleProcess.add(imple);
}
public Vector<String> getImpleProcess() {
return impleProcess;
}

}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public interface IProjectBuilder {
Project getProject();
void makeRequirement();

void makePrototype();

void makeScheduler();

void makeTables();

void makeAppFrameWork();

void programming();

void test();

void delivery();
}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public class ExamProjectBuilder implements IProjectBuilder {
private Project project;

public ExamProjectBuilder() {
this.project = new Project();
}

public Project getProject() {
return project;
}

@Override
public void makeRequirement() {
this.project.process("创建考试系统需求");

}

@Override
public void makePrototype() {
this.project.process("创建考试原型");
}

@Override
public void makeScheduler() {
this.project.process("创建考试计划");
}

@Override
public void makeTables() {
this.project.process("创建考试系统表");
}

@Override
public void makeAppFrameWork() {
this.project.process("创建考试应用架构");
}

@Override
public void programming() {
this.project.process("考试应用代码实现");
}

@Override
public void test() {
this.project.process("测试考试应用");
}

@Override
public void delivery() {
this.project.process("交付考试应用");
}
}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public class CRMProjectBuilder implements IProjectBuilder {
public CRMProjectBuilder() {
this.project = new Project();
}

public Project getProject() {
return project;
}

private Project project;

@Override
public void makeRequirement() {
this.project.process("创建CRM系统需求");
}

@Override
public void makePrototype() {
this.project.process("创建CRM原型");
}

@Override
public void makeScheduler() {
this.project.process("创建CRM计划");
}

@Override
public void makeTables() {
this.project.process("创建CRM系统表");
}

@Override
public void makeAppFrameWork() {
this.project.process("创建CRM应用架构");
}

@Override
public void programming() {
this.project.process("CRM应用代码实现");
}

@Override
public void test() {
this.project.process("测试CRM应用");
}

@Override
public void delivery() {
this.project.process("交付CRM应用");
}
}

package design.pattern.builder;

/**
* Created by Aaron on 15/9/13.
*/
public class Director {
private IProjectBuilder builder;
public Director(IProjectBuilder builder){
this.builder=builder;
}
public Project process(){
this.builder.makeRequirement();
this.builder.makePrototype();
this.builder.makeScheduler();
this.builder.makeAppFrameWork();
this.builder.makeTables();
this.builder.programming();
this.builder.test();
this.builder.delivery();
return builder.getProject();
}

public static void main(String[] args){
Director director = new Director(new CRMProjectBuilder());
Project project = director.process();
System.out.println(project.getImpleProcess());
}
}

//输出 [创建CRM系统需求, 创建CRM原型, 创建CRM计划, 创建CRM应用架构, 创建CRM系统表, CRM应用代码实现, 测试CRM应用, 交付CRM应用]

原型模式(Prototype);

GoF这样定义:

用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。

package design.pattern.prototype;

import java.io.*;
import java.util.Vector;

/**
* Created by Aaron on 15/9/13.
*/
public class DeepClonePrototype implements Cloneable,Serializable {
public Vector<String> attrs=new Vector<String>();

public Object deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}

public static void main(String[] args) throws Exception{
Object pro=new DeepClonePrototype().deepClone();
System.out.println(pro.getClass());
}

}

单例模式(Singleton);

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

package design.pattern.singleton;

/**
* Created by Aaron on 15/9/11.
*/
public class Singleton {
private Singleton() {

}

private static Singleton instance = null;

private static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
return instance = new Singleton();
} else {
return instance;
}
}
} else {
return instance;
}
}

public String getName() {
return Singleton.class.getName();
}

public static void main(String args[]) {
Singleton instance = Singleton.getInstance();
System.out.print(instance.getName());
}

}

设计模式之结构型模式

##结构型模式

描述在面向对象设计中,类和对象的几种结构关系,设计好了会为后续代码的维护带来很大的方便。

  • 外观模式(Facade);
  • 适配器模式(Adapter);
  • 代理模式(Proxy);
  • 装饰模式(Decorator);
  • 桥模式(Bridge);
  • 组合模式(Composite);
  • 享元模式(Flyweight);

###外观模式(Facade)又称门面模式;
GoF这样定义:

为子系统中的一组接口提供一个一致的界面, Facade 模式定义了一个高层 接口,这个接口使得这一子系统更加容易使用。

外观模式,在我理解就是给一组对象提供一个对外统计的操作方式 ,让外部使用者不用操心内部工作。如一个汽车,一个电脑,你点开机,硬盘,CPU,内存,显卡就都开始工作了,关机时也一样。这里对我们操作者来说其实就是一个开关。

``
package design.pattern.facade;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String[] args)throws InterruptedException{
Computer computer=new Computer();
computer.startup();
System.out.println("--------shutdown-----------");
computer.shutdown();
}
}

package design.pattern.facade;
/**
* Created by Aaron on 15/9/14.
*/
public class Computer {
private CPU cpu;
private Memory memory;
private GraphicsCard graphicsCard;
private Disk disk;

public Computer() {
this.cpu = new CPU();
this.memory = new Memory();
this.graphicsCard = new GraphicsCard();
this.disk = new Disk();
}

public void startup(){
this.cpu.startup();
this.memory.startup();
this.disk.startup();
this.graphicsCard.startup();
}
public void shutdown(){
this.graphicsCard.shutdown();
this.disk.shutdown();
this.memory.shutdown();
this.cpu.shutdown();
}



}

package design.pattern.facade;

/**
* Created by Aaron on 15/9/14.
*/
public class CPU {
public void startup(){
System.out.println(this.getClass().getSimpleName()+"启动");
}
public void shutdown(){
System.out.println(this.getClass().getSimpleName()+"关闭");
}
}

package design.pattern.facade;

/**
* Created by Aaron on 15/9/14.
*/
public class Disk {
public void startup(){
System.out.println(this.getClass().getSimpleName()+"启动");
}
public void shutdown(){
System.out.println(this.getClass().getSimpleName()+"关闭");
}
}

package design.pattern.facade;

/**
* Created by Aaron on 15/9/14.
*/
public class GraphicsCard {
public void startup(){
System.out.println(this.getClass().getSimpleName()+"启动");
}
public void shutdown(){
System.out.println(this.getClass().getSimpleName()+"关闭");
}
}

package design.pattern.facade;

/**
* Created by Aaron on 15/9/14.
*/
public class Memory {
public void startup(){
System.out.println(this.getClass().getSimpleName()+"启动");
}
public void shutdown(){
System.out.println(this.getClass().getSimpleName()+"关闭");
}
}

输出结果:

CPU启动
Memory启动
Disk启动
GraphicsCard启动
--------shutdown-----------
GraphicsCard关闭
Disk关闭
Memory关闭
CPU关闭

###适配器模式(Adapter);
GoF这样定义:

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

我的事例理解:如咱们家中常用的洗衣机,当我们要与我们的水龙头进行对接时,中间要借助一个中间者“转换头”,它在这里就起到了适配作用。

``
package design.pattern.adapter;

/**
* Created by Aaron on 15/9/14.
*/
public class WashingMachine {
public void connectPort(IWashFaucetAdapter washportadapter){
System.out.print(washportadapter.outToWashingPort()+" success!");
}
}

package design.pattern.adapter;

/**
* Created by Aaron on 15/9/14.
*/
public interface IWashFaucetAdapter {
String outToWashingPort();
}

package design.pattern.adapter;

/**
* Created by Aaron on 15/9/14.
*/
public class WashingFaucetAdapter extends Faucet implements IWashFaucetAdapter{

public String outToWashingPort(){
return "transform"+this.port()+" to washing port!";
}
}

package design.pattern.adapter;

/**
* Created by Aaron on 15/9/14.
* 水龙头
*/

public class Faucet {
public String port(){
System.out.print("facucet port .....");
return "facucet port";
}
}

package design.pattern.adapter;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String[] args){
// 创建水龙头、洗衣机、镶接头
WashingMachine washingMachine=new WashingMachine();
WashingFaucetAdapter washingFaucetAdapter= new WashingFaucetAdapter();
// 进行适配
washingMachine.connectPort(washingFaucetAdapter);

}
}

输出结果:

facucet port .....transformfacucet port to washing port! success!

###代理模式(Proxy);
GoF这样定义:

为其他对象提供一个代理以控制对这个对象的访问。

这里就以找工作为例吧,现在我们找工作都会通过找工作平台来进行找工作,因为他们有资源,他们比较专业。我们告诉他们要找什么样的工作他们就会给我们推荐什么样的工作,在这个环节中,类似51job,100offer这样的平台就是所谓的招聘代理。
他代理公司进行招人。同时也方便了我们去找工作。

下面是代码实现:

package design.pattern.proxy;

/**
* Created by Aaron on 15/9/14.
*/
public interface IRecruitment {
void recruitment(String user);
}

package design.pattern.proxy;

/**
* Created by Aaron on 15/9/14.
*/
public class FounderWork implements IRecruitment{
public void recruitment(String user){
System.out.println(this.getClass().getSimpleName()+"招聘员工"+user+"成功!");
}
}

package design.pattern.proxy;

/**
* Created by Aaron on 15/9/14.
*/
public class WorkProxy implements IRecruitment {
private IRecruitment recruitment;

public WorkProxy() {
this.recruitment = new FounderWork();
}

@Override
public void recruitment(String user) {
before();
this.recruitment.recruitment(user);
after();
}

public void before() {
System.out.println(this.getClass().getSimpleName() + "进行招聘前工作准备!");
}

public void after() {
System.out.println(this.getClass().getSimpleName() + "进行招聘完成后工作收尾!");
}

}


package design.pattern.proxy;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String[] args){
new WorkProxy().recruitment("Aaron");
}
}

输出:

WorkProxy进行招聘前工作准备!
FounderWork招聘员工Aaron成功!
WorkProxy进行招聘完成后工作收尾!

###装饰模式(Decorator);
GoF这样定义:

动态地给一个对象添加一些额外的职责。就扩展功能而言, Decorator 模 式比生成子类方式更为灵活。

我们可以拿我们的扩音器为例,假如一个mp3的有声音,那么它的声音不是很大,稍微远一点我们就不能听到了,这里就会用一个扩音器,放在mp3旁边,离稍微远点也能享受音乐的快乐了。

这里,扩音器就是装饰器,他使mp3的声音变大。有时扩音器也可以改变声音的音质,变的更好听。

下面是代码实现:

package design.pattern.decorator;

/**
* Created by Aaron on 15/9/14.
*/
public interface ISoundable {
void sound();
}

package design.pattern.decorator;

/**
* Created by Aaron on 15/9/14.
*/
public class MP3 implements ISoundable{
public void sound(){
System.out.println("small sound from mp3!");
}
}

package design.pattern.decorator;

/**
* Created by Aaron on 15/9/14.
*/
public class SoundDecorator implements ISoundable {
private ISoundable soundable;

public SoundDecorator(ISoundable soundable) {
this.soundable = soundable;
}

public void sound(){
this.soundable.sound();
System.out.println("make sound beautiful");
System.out.println("make sound aloud ");
}
}

package design.pattern.decorator;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String[] args){
new SoundDecorator(new MP3()).sound();
}
}

输出:

small sound from mp3!
make sound beautiful
make sound aloud 

###桥接模式(Bridge);
GoF这样定义:

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

这里还举一个生活中常用到的例子,洗衣机有多种,但我们当我们没有接到水龙头上的管子时,我们可以去商店里买,这里可能会有大小长短各不相同的管子,但都可以与我们的洗衣机相连接进行使用。

这里我们变化的是多种洗衣机和多种管子,我们为洗衣机做一个抽像类。可以设置不同的管子。

``
package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
*/
public interface IPip {
String color();
}

package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
* 水龙头
*/

public class RedPip implements IPip{
public String color(){
return "Red";
}
}

package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
* 水龙头
*/

public class BluePip implements IPip{
public String color(){
return "blue pip";
}
}


package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
*/
public abstract class AbstractWashingMachine {
private IPip pip;

public IPip getPip() {
return pip;
}

public void setPip(IPip pip) {
this.pip = pip;
System.out.println(this.getClass().getSimpleName()+" set "+pip.color()+" "+pip.getClass().getSimpleName());
}
}


package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
*/
public class ChinaWashingMachine extends AbstractWashingMachine {
}

package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
*/
public class HaierWashingMachine extends AbstractWashingMachine {
}

package design.pattern.bridge;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String[] args){
new HaierWashingMachine().setPip(new BluePip());
new HaierWashingMachine().setPip(new RedPip());
new ChinaWashingMachine().setPip(new BluePip());
}
}

输出:

HaierWashingMachine set blue pip BluePip
HaierWashingMachine set Red RedPip
ChinaWashingMachine set blue pip BluePip

###组合模式(Composite);
GoF这样定义:

将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使 得客户对单个对象和复合对象的使用具有一致性。

这里我们最常见的就是公司与部门的关系,其实就是整体与部分的关系。

代码

package design.pattern.composite;

import java.util.Vector;

/**
* Created by Aaron on 15/9/14.
*/
public abstract class AbstractCompany {
private String name;
private Vector<AbstractCompany> companys=new Vector<AbstractCompany>();
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
public void display(int deep) {
StringBuilder sb=new StringBuilder();
for(int i=0;i<deep;i++){
sb.append("\t");
}
sb.append(this.getName());
System.out.println(sb.toString());
int l = this.getCompanys().size();
if (l > 0) {
for (int i = 0; i < l; i++) {
this.getCompanys().get(i).display(deep+2);
}
}
}
public Vector<AbstractCompany> getCompanys() {
return companys;
}
public void removeCompany(AbstractCompany company){
this.companys.remove(company);
}
public void addCompany(AbstractCompany company) {
this.companys.add(company);
}
}

package design.pattern.composite;

/**
* Created by Aaron on 15/9/14.
*/
public class Company extends AbstractCompany {
public Company(String name) {
this.setName(name);
}

}

package design.pattern.composite;

/**
* Created by Aaron on 15/9/14.
*/
public class TechDepartment extends AbstractCompany {
public TechDepartment() {
}
public TechDepartment(String name) {
this.setName(name);
}
}

package design.pattern.composite;

/**
* Created by Aaron on 15/9/14.
*/
public class UIDepartment extends AbstractCompany {
public UIDepartment(String name) {
this.setName(name);
}

public UIDepartment() {
}
}

package design.pattern.composite;

/**
* Created by Aaron on 15/9/14.
*/
public class CEO {
public static void main(String[] args) {
AbstractCompany company = new Company("总公司");
AbstractCompany abc = new TechDepartment("技术一部");
company.addCompany(abc);
abc = new TechDepartment("技术二部");
company.addCompany(abc);
abc = new TechDepartment("技术三部");
company.addCompany(abc);
abc = new UIDepartment("UI一部");
company.addCompany(abc);
abc = new UIDepartment("UI二部");
company.addCompany(abc);
abc = new UIDepartment("UI三部");
company.addCompany(abc);
AbstractCompany abc1 = new UIDepartment("UI一组");
abc.addCompany(abc1);
abc1 = new UIDepartment("UI二组");
abc.addCompany(abc1);
abc1 = new UIDepartment("UI三组");
abc.addCompany(abc1);
company.display(0);
}
}


输出:

总公司
        技术一部
        技术二部
        技术三部
        UI一部
        UI二部
        UI三部
                UI一组
                UI二组
                UI三组

###享元模式(Flyweight)
GoF这样定义:

运用共享技术有效地支持大量细粒度的对象。

咱们这里会想到数据库连接池,对,就是它,咱们先看一下类图。

`示例代码如下:`
package design.pattern.flayweight;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;

/**
* Created by Aaron on 15/9/14.
*/
public class ConnectionPool {
private Vector<Connection> pool;
private static ConnectionPool instance;
private int poolSize=10;
private String url = "jdbc:mysql://127.0.0.1:3306/mysql";
private String username = "root";
private String password = "root";
private String driverClassName = "com.mysql.jdbc.Driver";
private ConnectionPool(){
this.pool=new Vector<Connection>();

for (int i = 0; i < poolSize; i++) {
try {
Class.forName(driverClassName);
pool.add(DriverManager.getConnection(url, username, password));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}

public static synchronized ConnectionPool getInstance(){
if(instance==null){
return instance=new ConnectionPool();
}
return instance;
}

public synchronized Connection getConnection(){
Connection connection=null;
if(pool.size()>0){
connection=pool.get(0);
pool.remove(connection);
}
return connection;
}

public synchronized void release(Connection conn){
pool.add(0,conn);
}

}

package design.pattern.flayweight;

import java.sql.Connection;

/**
* Created by Aaron on 15/9/14.
*/
public class User {
public static void main(String args[]){
ConnectionPool pool=ConnectionPool.getInstance();
Connection connection=pool.getConnection();
System.out.println(connection);
connection=pool.getConnection();
System.out.println(connection);
pool.release(connection);
connection=pool.getConnection();
System.out.println(connection);
}
}


输出:

com.mysql.jdbc.JDBC4Connection@2d8e6db6
com.mysql.jdbc.JDBC4Connection@23ab930d
com.mysql.jdbc.JDBC4Connection@23ab930d

JAVA设计模式之行为型模式

##行为型模式

对象的创建和结构定义好后,就是他们的行为的设计了。

  • 模板方法模式(Template Method);
  • 观察者模式(Observer);
  • 状态模式(State);
  • 策略模式(Strategy);
  • 职责链模式(Chain of Responsibility);
  • 命令模式(Command);
  • 访问者模式(Visitor);
  • 调停者模式(Mediator);
  • 备忘录模式(Memento);
  • 迭代器模式(Iterator);
  • 解释器模式(Interpreter);

模板方法模式(Template Method);

GoF这样定义:

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

这里我们以画布上画画为例,我们定义一抽象类,其中定义一个渲染方法,渲染时有两个步骤,一个画背景,二能画主体,三加印章。
咱们这里画一个圆和画一个矩形,抽象类中定义渲染时的先后流程,具体的实现有具体的子类进行实现。

代码如下:

package design.pattern.temlatemothod;

/**
* Created by Aaron on 15/9/16.
*/
public abstract class AbstractShape {
public void render(){
this.drawBackground();
this.drawGraphics();
this.drawSignature();
}
abstract void drawSignature();
abstract void drawBackground();
abstract void drawGraphics();

}

package design.pattern.temlatemothod;

/**
* Created by Aaron on 15/9/16.
*/
public class CircleShape extends AbstractShape {
@Override
public void drawSignature() {
System.out.println("draw circle signature!");
}

@Override
public void drawBackground() {
System.out.println("draw circle background! ");
}

@Override
public void drawGraphics() {
System.out.println("draw circle graphics!");
}
}

package design.pattern.temlatemothod;

/**
* Created by Aaron on 15/9/16.
*/
public class RectShape extends AbstractShape {
@Override
public void drawSignature() {
System.out.println("draw rect signature!");
}

@Override
public void drawBackground() {
System.out.println("draw rect background! ");
}

@Override
public void drawGraphics() {
System.out.println("draw rect graphics!");
}
}

package design.pattern.temlatemothod;

/**
* Created by Aaron on 15/9/16.
*/
public class User {
public static void main(String args[]){
new CircleShape().render();
System.out.println("-----");
new RectShape().render();
}
}

输出结果:

draw circle background! 
draw circle graphics!
draw circle signature!
-----
draw circle background! 
draw circle graphics!
draw circle signature!

观察者模式(Observer);

GoF这样定义:

定义对象间的一种一对多的依赖关系 , 以便当一个对象的状态发生改变时 , 所有依赖于它的对象都得到通知并自动刷新。

我们常常会遇到,当一个事件发生时,会有一些监听者进行相应的响应。这里我们的例子是, 当GPS发生变化时,它的订阅者的update的方法就会被调用。

`下面是示例代码:`
package design.pattern.observer;

import java.lang.reflect.Array;
import java.util.ArrayList;

/**
* Created by Aaron on 15/9/16.
*/
public abstract class Subject {
private ArrayList<Observer> observers=new ArrayList<Observer>();
public void addObserver(Observer observer){
this.observers.add(observer);
}
public void removeObserver(Observer observer){
this.observers.remove(observer);
}
public void notifyObserver(){
for(Observer observer:observers){
observer.update(this);
}
}
}

package design.pattern.observer;

import java.awt.*;

/**
* Created by Aaron on 15/9/16.
*/
public class GPSSubject extends Subject {
private Point point;
public void move(Point point){
this.point=point;
this.notifyObserver();
}
}

package design.pattern.observer;

/**
* Created by Aaron on 15/9/16.
*/
public abstract class Observer {
public Observer(){

}
public abstract void update(Subject subject);

}


package design.pattern.observer;

/**
* Created by Aaron on 15/9/16.
*/
public class MapObserver extends Observer {
@Override
public void update(Subject subject) {
System.out.println(this.getClass().getSimpleName()+"_"+this.hashCode()+" observer:"+subject.getClass().getSimpleName()+" position changed;");
}
}

package design.pattern.observer;

import java.awt.*;

/**
* Created by Aaron on 15/9/16.
*/
public class User {
public static void main(String[] args){
GPSSubject subject=new GPSSubject();
subject.addObserver(new MapObserver());
Observer observer1=null;
subject.addObserver(observer1=new MapObserver());
subject.move(new Point(200, 400));
System.out.println("remove one observer from subject's observer list!");
subject.removeObserver(observer1);
subject.move(new Point(200,400));
}
}

状态模式(State);

GoF这样定义: 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它
所属的类。

以下是示例代码:

package design.pattern.state;

/**
* Created by Aaron on 15/9/20.
*/
public class Context extends AbstractLifeState {
public static OpeningState openingState = new OpeningState();
public static ClosingState closingState = new ClosingState();
public static RunningState runningState = new RunningState();
public static StoppingState stoppingState = new StoppingState();
private AbstractLifeState lifeState;

public Context() {
}

public AbstractLifeState getLifeState() {
return lifeState;
}

public void setLifeState(AbstractLifeState lifeState) {
this.lifeState = lifeState;
this.lifeState.setContext(this);
}

@Override
public void open() {
this.lifeState.open();
}

@Override
public void close() {
this.lifeState.close();
}

@Override
public void run() {
this.lifeState.run();
}

@Override
public void stop() {
this.lifeState.stop();
}
}

package design.pattern.state;

/**
* Created by Aaron on 15/9/20.
*/
public abstract class AbstractLifeState {
protected Context context;

public void setContext(Context context) {
this.context = context;
}

public abstract void open();
public abstract void close();
public abstract void run();
public abstract void stop();
}

package design.pattern.state;

/**
* Created by Aaron on 15/9/20.
*/
public class OpeningState extends AbstractLifeState {
@Override
public void open() {
System.out.println(this.getClass().getSimpleName() + ": operate open");
}

@Override
public void close() {
System.out.println(this.getClass().getSimpleName() + ": operate close");
this.context.setLifeState(Context.closingState);
}

@Override
public void run() {
System.out.println(this.getClass().getSimpleName() + ": operate run");
this.context.setLifeState(Context.runningState);
}

@Override
public void stop() {
System.out.println(this.getClass().getSimpleName()+": operate stop");
this.context.setLifeState(Context.stoppingState);
}
}

package design.pattern.state;

/**
* Created by Aaron on 15/9/20.
*/
public class RunningState extends AbstractLifeState {
@Override
public void open() {
System.out.println(this.getClass().getSimpleName() + ": operate open");
context.setLifeState(Context.openingState);
}

@Override
public void close() {
System.out.println(this.getClass().getSimpleName()+": operate close");
context.setLifeState(Context.closingState);
}

@Override
public void run() {
System.out.println(this.getClass().getSimpleName()+": operate run");
}

@Override
public void stop() {
System.out.println(this.getClass().getSimpleName()+": operate stop");
context.setLifeState(Context.stoppingState);
}
}

package design.pattern.state;

/**
* Created by Aaron on 15/9/20.
*/
public class StoppingState extends AbstractLifeState {
@Override
public void open() {
System.out.println(this.getClass().getSimpleName() + ": operate open");
}

@Override
public void close() {
System.out.println(this.getClass().getSimpleName()+": operate close");
}

@Override
public void run() {
System.out.println(this.getClass().getSimpleName()+": operate run");
}

@Override
public void stop() {
System.out.println(this.getClass().getSimpleName()+": operate stop");
}
}

package design.pattern.state;

/**
* Created by Aaron on 15/9/20.
*/
public class ClosingState extends AbstractLifeState {
@Override
public void open() {
System.out.println(this.getClass().getSimpleName() + ": operate open");
context.setLifeState(Context.openingState);
}

@Override
public void close() {
System.out.println(this.getClass().getSimpleName() + ": operate close");
}

@Override
public void run() {
System.out.println(this.getClass().getSimpleName()+": operate run");
context.setLifeState(Context.runningState);
}

@Override
public void stop() {
System.out.println(this.getClass().getSimpleName()+": operate stop");
context.setLifeState(Context.stoppingState);
}
}

package design.pattern.state;

import design.pattern.flayweight.ConnectionPool;

/**
* Created by Aaron on 15/9/20.
*/
public class User {
public static void main(String[] args){
Context context=new Context();
context.setLifeState(Context.closingState);
context.open();
context.run();
context.close();

}
}

策略模式(Strategy);

GoF这样定义:

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。

计算器的实现,其中计算的

以下是示例代码:

package design.pattern.strategy;

/**
* Created by Aaron on 15/9/21.
*/
public interface ICalculate {
double calculate(double a,double b);
}

package design.pattern.strategy;

/**
* Created by Aaron on 15/9/21.
*/
public class AddCalculate implements ICalculate {
public double calculate(double a, double b) {
return a+b;
}
}

package design.pattern.strategy;

/**
* Created by Aaron on 15/9/21.
*/
public class DivisionCalculate implements ICalculate {
public double calculate(double a, double b) {
return a/b;
}
}

package design.pattern.strategy;

/**
* Created by Aaron on 15/9/21.
*/
public class SubtractionCalculate implements ICalculate {
public double calculate(double a, double b) {
return a-b;
}
}

package design.pattern.strategy;

/**
* Created by Aaron on 15/9/21.
*/
public class Context {
private ICalculate calculate;
public Context(ICalculate calculate){
this.calculate=calculate;
}

public ICalculate getCalculate() {
return calculate;
}

public void setCalculate(ICalculate calculate) {
this.calculate = calculate;
}

public double calculate(double a,double b){
return this.calculate.calculate(a,b);
}
}

package design.pattern.strategy;

/**
* Created by Aaron on 15/9/21.
*/
public class User {
public static void main(String args[]){
Context context =new Context(new AddCalculate());
double result=context.calculate(20.0,30.3);
System.out.println(result);
context.setCalculate(new DivisionCalculate());
System.out.println(context.calculate(20,40));
}
}

结果输出:

50.3
0.5

职责链模式(Chain of Responsibility);

GoF这样定义:

典型的事例就是我们在Spring中的拦截器和Servlet中的Filter,它们都是现成的责任链模式。

`以下是示例代码:`
package design.pattern.responsibilitychain;

/**
* Created by Aaron on 15/9/29.
*/
public abstract class Handler {
protected Handler successor;

public abstract void process();

public Handler getSuccessor() {
return successor;
}

public void setSuccessor(Handler successor) {
this.successor = successor;
}
}

package design.pattern.responsibilitychain;

/**
* Created by Aaron on 15/9/29.
*/
public class LoggerHandler extends Handler {
@Override
public void process() {
if(getSuccessor()!=null){
System.out.println(getClass().getSimpleName()+",处理请求,并调用下一个处理者");
getSuccessor().process();
}else{
System.out.println(getClass().getSimpleName()+",仅处理,无下一处理者");
}
}
}

package design.pattern.responsibilitychain;

/**
* Created by Aaron on 15/9/29.
*/
public class ValidateHandler extends Handler {
@Override
public void process() {
if(getSuccessor()!=null){
System.out.println(getClass().getSimpleName()+",处理请求,并调用下一个处理者");
getSuccessor().process();
}else{
System.out.println(getClass().getSimpleName()+",仅处理,无下一处理者");
}
}
}

package design.pattern.responsibilitychain;

/**
* Created by Aaron on 15/9/29.
*/
public class User {
public static void main(String[] args) {
Handler validate = new ValidateHandler();
Handler handler = new LoggerHandler();
validate.setSuccessor(handler);
validate.process();
}
}

输出:

ValidateHandler,处理请求,并调用下一个处理者
LoggerHandler,仅处理,无下一处理者

命令模式(Command);

GoF这样定义:

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数 化;对请求排队或记录请求日志,以及支持可取消的操作。

AudioPlayer系统(转)

  小女孩茱丽(Julia)有一个盒式录音机,此录音机有播音(Play)、倒带(Rewind)和停止(Stop)功能,录音机的键盘便是请求者(Invoker)角色;茱丽(Julia)是客户端角色,而录音机便是接收者角色。Command类扮演抽象命令角色,而PlayCommand、StopCommand和RewindCommand便是具体命令类。茱丽(Julia)不需要知道播音(play)、倒带(rewind)和停止(stop)功能是怎么具体执行的,这些命令执行的细节全都由键盘(Keypad)具体实施。茱丽(Julia)只需要在键盘上按下相应的键便可以了。

  录音机是典型的命令模式。录音机按键把客户端与录音机的操作细节分割开来。

`以下是示例代码:`
package design.pattern.command;

/**
* Created by Aaron on 15/9/29.
*/
public class AudioPlay {
public void play(){
System.out.println("播放....");
}
public void rewind(){
System.out.println("倒带....");
}
public void stop(){
System.out.println("停止....");
}

}

package design.pattern.command;

/**
* Created by Aaron on 15/9/29.
*/
public interface Command {
void execute();
}


package design.pattern.command;

/**
* Created by Aaron on 15/9/29.
*/
public class PlayCommand implements Command {
private AudioPlay audioPlay;

public PlayCommand(AudioPlay audioPlay) {
this.audioPlay = audioPlay;
}

public void execute() {
this.audioPlay.play();
}
}

package design.pattern.command;

/**
* Created by Aaron on 15/9/29.
*/
public class RewindCommand implements Command {
private AudioPlay audioPlay;

public RewindCommand(AudioPlay audioPlay) {
this.audioPlay = audioPlay;
}
public void execute() {
this.audioPlay.rewind();
}
}

package design.pattern.command;

/**
* Created by Aaron on 15/9/29.
*/
public class StopCommand implements Command {
private AudioPlay audioPlay;

public StopCommand(AudioPlay audioPlay) {
this.audioPlay = audioPlay;
}
public void execute() {
this.audioPlay.stop();
}
}

package design.pattern.command;

/**
* Created by Aaron on 15/9/29.
*/
public class Keypad {
private Command playCommand;
private Command rewindCommand;
private Command stopCommand;

public void setPlayCommand(Command playCommand) {
this.playCommand = playCommand;
}

public void setRewindCommand(Command rewindCommand) {
this.rewindCommand = rewindCommand;
}

public void setStopCommand(Command stopCommand) {
this.stopCommand = stopCommand;
}

public void play(){
playCommand.execute();
}
public void rewind(){
rewindCommand.execute();
}
public void stop(){
stopCommand.execute();
}
}

package design.pattern.command;

/**
* Created by Aaron on 15/9/29.
*/
public class User {
public static void main(String[] args) {
AudioPlay audioPlay = new AudioPlay();
PlayCommand playCommand = new PlayCommand(audioPlay);
RewindCommand rewindCommand = new RewindCommand(audioPlay);
StopCommand stopCommand = new StopCommand(audioPlay);

Keypad keypad=new Keypad();
keypad.setPlayCommand(playCommand);
keypad.setRewindCommand(rewindCommand);
keypad.setStopCommand(stopCommand);

keypad.play();
keypad.rewind();
keypad.stop();
keypad.play();
keypad.stop();

}
}

输出结果:

播放....
倒带....
停止....
播放....
停止....

访问者模式(Visitor);

GoF这样定义:

表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元
素的类的前提下定义作用于这些元素的新操作。

`以下是示例代码:`
```
## 调停者模式(Mediator);
GoF这样定义:
>用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互

<div class="col-xs-12">
<img src='' class='col-lg-offset-3 col-lg-6 col-xs-12 thumbnail'/>
</div>
`以下是示例代码:`
```java
## 备忘录模式(Memento); GoF这样定义: > 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。
`以下是示例代码:`
```
## 迭代器模式(Iterator);
GoF这样定义:
>提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。
<div class="col-xs-12">
<img src='' class='col-lg-offset-3 col-lg-6 col-xs-12 thumbnail'/>
</div>
`以下是示例代码:`
```java
##解释器模式(Interpreter) GoF这样定义: >给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
`以下是示例代码:` ```java ```°