zoukankan      html  css  js  c++  java
  • Java设计模式

    第1 章策略模式【Strategy Pattern】
    刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是按天机拆开解决棘手问题,
    嘿,还别说,真是解决了大问题,搞到最后是周瑜陪了夫人又折兵呀,那咱们先看看这个场景是什么样子
    的。
    先说这个场景中的要素:三个妙计,一个锦囊,一个赵云,妙计是小亮同志给的,妙计是放置在锦囊
    里,俗称就是锦囊妙计嘛,那赵云就是一个干活的人,从锦囊中取出妙计,执行,然后获胜,用 JAVA 程序
    怎么表现这个呢?我们先看类图:
    三个妙计是同一类型的东东,那咱就写个接口:
    package com.cbf4life.strategy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 首先定一个策略接口,这是诸葛亮老人家给赵云的三个锦囊妙计的接口
    *
    */
    public interface IStrategy {
    //每个锦囊妙计都是一个可执行的算法
    public void operate();
    }
    然后再写三个实现类,有三个妙计嘛:
    package com.cbf4life.strategy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 找乔国老帮忙,使孙权不能杀刘备
    */
    public class BackDoor implements IStrategy {
    public void operate() {
    System.out.println("找乔国老帮忙,让吴国太给孙权施加压力");
    }
    }
    package com.cbf4life.strategy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 求吴国太开个绿灯
    */
    public class GivenGreenLight implements IStrategy {
    public void operate() {
    System.out.println("求吴国太开个绿灯,放行! ");
    }
    }
    package com.cbf4life.strategy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 孙夫人断后,挡住追兵
    */
    public class BlockEnemy implements IStrategy {
    public void operate() {
    System.out.println("孙夫人断后,挡住追兵");
    }
    }
    好了,大家看看,三个妙计是有了,那需要有个地方放这些妙计呀,放锦囊呀:
    package com.cbf4life.strategy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 计谋有了,那还要有锦囊
    */
    public class Context {
    //构造函数,你要使用那个妙计
    private IStrategy straegy;
    public Context(IStrategy strategy){
    this.straegy = strategy;
    }
    //使用计谋了,看我出招了
    public void operate(){
    this.straegy.operate();
    }
    }
    然后就是赵云雄赳赳的揣着三个锦囊,拉着已步入老年行列的、还想着娶纯情少女的、色迷迷的刘老
    爷子去入赘了,嗨,还别说,小亮的三个妙计还真是不错,瞅瞅:
    package com.cbf4life.strategy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    */
    public class ZhaoYun {
    /**
    * 赵云出场了,他根据诸葛亮给他的交代,依次拆开妙计
    */
    public static void main(String[] args) {
    Context context;
    //刚刚到吴国的时候拆第一个
    System.out.println("-----------刚刚到吴国的时候拆第一个-------------");
    context = new Context(new BackDoor()); //拿到妙计
    context.operate(); //拆开执行
    System.out.println(" ");
    //刘备乐不思蜀了,拆第二个了
    System.out.println("-----------刘备乐不思蜀了,拆第二个了-------------");
    context = new Context(new GivenGreenLight());
    context.operate(); //执行了第二个锦囊了
    System.out.println(" ");
    //孙权的小兵追了,咋办?拆第三个
    System.out.println("-----------孙权的小兵追了,咋办?拆第三个
    -------------");
    context = new Context(new BlockEnemy());
    context.operate(); //孙夫人退兵
    System.out.println(" ");
    /*
    *问题来了:赵云实际不知道是那个策略呀,他只知道拆第一个锦囊,
    *而不知道是BackDoor这个妙计,咋办? 似乎这个策略模式已经把计谋名称写出来了
    *
    * 错! BackDoor、 GivenGreenLight、 BlockEnemy只是一个代码,你写成first、 second、
    third,没人会说你错!
    *
    * 策略模式的好处就是:体现了高内聚低耦合的特性呀,缺点嘛,这个那个,我回去再查查
    */
    }
    }
    就这三招,搞的周郎是“陪了夫人又折兵”呀!这就是策略模式,高内聚低耦合的特点也表现出来了,
    还有一个就是扩展性,也就是 OCP 原则,策略类可以继续增加下去,只要修改 Context.java 就可以了,这
    个不多说了,自己领会吧。

    第2 章代理模式【Proxy Pattern】
    什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道
    被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人虽然不能干活,但是被
    代理的人能干活呀。
    比如西门庆找潘金莲,那潘金莲不好意思答复呀,咋办,找那个王婆做代理,表现在程序上时这样的:
    先定义一种类型的女人:
    package com.cbf4life.proxy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 定义一种类型的女人,王婆和潘金莲都属于这个类型的女人
    */
    public interface KindWomen {
    //这种类型的女人能做什么事情呢?
    public void makeEyesWithMan(); //抛媚眼
    public void happyWithMan(); //happy what? You know that!
    }
    一种类型嘛,那肯定是接口,然后定义潘金莲:
    package com.cbf4life.proxy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 定一个潘金莲是什么样的人
    */
    public class PanJinLian implements KindWomen {
    public void happyWithMan() {
    System.out.println("潘金莲在和男人做那个.....");
    }
    public void makeEyesWithMan() {
    System.out.println("潘金莲抛媚眼");
    }
    }
    再定一个丑陋的王婆:
    package com.cbf4life.proxy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 王婆这个人老聪明了,她太老了,是个男人都看不上,
    * 但是她有智慧有经验呀,她作为一类女人的代理!
    */
    public class WangPo implements KindWomen {
    private KindWomen kindWomen;
    public WangPo(){ //默认的话,是潘金莲的代理
    this.kindWomen = new PanJinLian();
    }
    //她可以是KindWomen的任何一个女人的代理,只要你是这一类型
    public WangPo(KindWomen kindWomen){
    this.kindWomen = kindWomen;
    }
    public void happyWithMan() {
    this.kindWomen.happyWithMan(); //自己老了,干不了,可以让年轻的代替
    }
    public void makeEyesWithMan() {
    this.kindWomen.makeEyesWithMan(); //王婆这么大年龄了,谁看她抛媚眼?!
    }
    }
    两个女主角都上场了,男主角也该出现了:
    package com.cbf4life.proxy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 定义一个西门庆,这人色中饿鬼
    */
    public class XiMenQing {
    /*
    * 水浒里是这样写的:西门庆被潘金莲用竹竿敲了一下难道,痴迷了,
    * 被王婆看到了, 就开始撮合两人好事,王婆作为潘金莲的代理人
    * 收了不少好处费,那我们假设一下:
    * 如果没有王婆在中间牵线,这两个不要脸的能成吗?难说的很!
    */
    public static void main(String[] args) {
    //把王婆叫出来
    WangPo wangPo = new WangPo();
    //然后西门庆就说,我要和潘金莲happy,然后王婆就安排了西门庆丢筷子的那出戏:
    wangPo.makeEyesWithMan(); //看到没,虽然表面上时王婆在做,实际上爽的是潘金莲
    wangPo.happyWithMan(); }
    }
    那这就是活生生的一个例子,通过代理人实现了某种目的,如果真去掉王婆这个中间环节,直接是西
    门庆和潘金莲勾搭,估计很难成就武松杀嫂事件。
    那我们再考虑一下,水浒里还有没有这类型的女人?有,卢俊义的老婆贾氏(就是和那个固管家苟合
    的那个),这名字起的:“假使”,那我们也让王婆做她的代理:
    把贾氏素描出来:
    package com.cbf4life.proxy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    */
    public class JiaShi implements KindWomen {
    public void happyWithMan() {
    System.out.println("贾氏正在Happy中......");
    }
    public void makeEyesWithMan() {
    System.out.println("贾氏抛媚眼");
    }
    }
    西门庆勾贾氏:
    package com.cbf4life.proxy;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 定义一个西门庆,这人色中饿鬼
    */
    public class XiMenQing {
    public static void main(String[] args) {
    //改编一下历史,贾氏被西门庆勾走:
    JiaShi jiaShi = new JiaShi();
    WangPo wangPo = new WangPo(jiaShi); //让王婆作为贾氏的代理人
    wangPo.makeEyesWithMan();
    wangPo.happyWithMan();
    }
    }
    说完这个故事,那额总结一下,代理模式主要使用了 Java 的多态,干活的是被代理类,代理类主要是
    接活,你让我干活,好,我交给幕后的类去干,你满意就成,那怎么知道被代理类能不能干呢?同根就成,
    大家知根知底,你能做啥,我能做啥都清楚的很,同一个接口呗。


    第3 章单例模式【Singleton Pattern】
    这个模式是很有意思,而且比较简单,但是我还是要说因为它使用的是如此的广泛,如此的有人缘,
    单例就是单一、独苗的意思,那什么是独一份呢?你的思维是独一份,除此之外还有什么不能山寨的呢?
    我们举个比较难复制的对象:皇帝
    中国的历史上很少出现两个皇帝并存的时期,是有,但不多,那我们就认为皇帝是个单例模式,在这
    个场景中,有皇帝,有大臣,大臣是天天要上朝参见皇帝的,今天参拜的皇帝应该和昨天、前天的一样(过
    渡期的不考虑,别找茬哦),大臣磕完头,抬头一看,嗨,还是昨天那个皇帝,单例模式,绝对的单例模式,
    先看类图:
    然后我们看程序实现,先定一个皇帝:
    package com.cbf4life.singleton1;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 中国的历史上一般都是一个朝代一个皇帝,有两个皇帝的话,必然要PK出一个皇帝出来
    */
    public class Emperor {
    private static Emperor emperor = null; //定义一个皇帝放在那里,然后给这个皇帝名字
    private Emperor(){
    //世俗和道德约束你,目的就是不让你产生第二个皇帝
    }
    public static Emperor getInstance(){
    if(emperor == null){ //如果皇帝还没有定义,那就定一个
    emperor = new Emperor();
    }
    return emperor;
    }
    //皇帝叫什么名字呀
    public static void emperorInfo(){
    System.out.println("我就是皇帝某某某....");
    }
    }
    然后定义大臣:
    package com.cbf4life.singleton1;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 大臣是天天要面见皇帝,今天见的皇帝和昨天的,前天不一样那就出问题了!
    */
    @SuppressWarnings("all")
    public class Minister {
    /**
    * @param args
    */
    public static void main(String[] args) {
    //第一天
    Emperor emperor1=Emperor.getInstance();
    emperor1.emperorInfo(); //第一天见的皇帝叫什么名字呢?
    //第二天
    Emperor emperor2=Emperor.getInstance();
    Emperor.emperorInfo();
    //第三天
    Emperor emperor3=Emperor.getInstance();
    emperor2.emperorInfo();
    //三天见的皇帝都是同一个人,荣幸吧!
    }
    }
    看到没,大臣天天见到的都是同一个皇帝,不会产生错乱情况,反正都是一个皇帝,是好是坏就这一
    个,只要提到皇帝,大家都知道指的是谁,清晰,而又明确。问题是这是通常情况,还有个例的,如同一
    个时期同一个朝代有两个皇帝,怎么办?
    单例模式很简单,就是在构造函数中多了加一个构造函数,访问权限是 private 的就可以了,这个模
    式是简单,但是简单中透着风险,风险?什么风险?在一个 B/S 项目中,每个 HTTP Request 请求到 J2EE
    的容器上后都创建了一个线程,每个线程都要创建同一个单例对象,怎么办?,好,我们写一个通用的单例程
    序,然后分析一下:
    package com.cbf4life.singleton3;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 通用单例模式
    */
    @SuppressWarnings("all")
    public class SingletonPattern {
    private static SingletonPattern singletonPattern= null;
    //限制住不能直接产生一个实例
    private SingletonPattern(){
    }
    public SingletonPattern getInstance(){
    if(this.singletonPattern == null){ //如果还没有实例,则创建一个
    this.singletonPattern = new SingletonPattern();
    }
    return this.singletonPattern;
    }
    }
    我们来看黄色的那一部分,假如现在有两个线程 A 和线程 B,线程 A 执行到 this.singletonPattern =
    new SingletonPattern(),正在申请内存分配,可能需要 0.001 微秒,就在这 0.001 微秒之内,线程 B 执
    行到 if(this.singletonPattern == null),你说这个时候这个判断条件是 true 还是 false?是 true,那
    然后呢?线程 B 也往下走,于是乎就在内存中就有两个 SingletonPattern 的实例了,看看是不是出问题了?
    如果你这个单例是去拿一个序列号或者创建一个信号资源的时候,会怎么样?业务逻辑混乱!数据一致性
    校验失败!最重要的是你从代码上还看不出什么问题,这才是最要命的!因为这种情况基本上你是重现不
    了的,不寒而栗吧,那怎么修改?有很多种方案,我就说一种,能简单的、彻底解决问题的方案:
    package com.cbf4life.singleton3;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 通用单例模式
    */
    @SuppressWarnings("all")
    public class SingletonPattern {
    private static final SingletonPattern singletonPattern= new
    SingletonPattern();
    //限制住不能直接产生一个实例
    private SingletonPattern(){
    }
    public synchronized static SingletonPattern getInstance(){
    return singletonPattern;
    }
    }
    直接 new 一个对象传递给类的成员变量 singletonpattern,你要的时候 getInstance() 直接返回给
    你,解决问题!
     

     

    第4 章多例模式【Multition Pattern】
    这种情况有没有?有!大点声,有没有? 有!, 是,确实有,就出现在明朝,那三国期间的算不算,
    不算,各自称帝,各有各的地盘,国号不同。大家还记得那首诗《石灰吟》吗?作者是谁?于谦,他是被
    谁杀死的?明英宗朱祁镇,对,就是那个在土木堡之变中被瓦刺俘虏的皇帝,被俘虏后,他弟弟朱祁钰当
    上了皇帝,就是明景帝,估计当上皇帝后乐疯了,忘记把老哥朱祁镇削为太上皇了,我 Shit,在中国的历
    史上就这个时期是有 2 个皇帝,你说这期间的大臣多郁闷,两个皇帝耶,两个精神依附对象呀。
    这个场景放到我们设计模式中就是叫有上限的多例模式 (没上限的多例模式太容易了,和你直接 new 一
    个对象没啥差别,不讨论)怎么实现呢,看我出招,先看类图:
    然后看程序,先把两个皇帝定义出来:
    package com.cbf4life.singleton2;
    import java.util.ArrayList;
    import java.util.Random;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 中国的历史上一般都是一个朝代一个皇帝,有两个皇帝的话,必然要PK出一个皇帝出来。
    * 问题出来了:如果真在一个时间,中国出现了两个皇帝怎么办?比如明朝土木堡之变后,
    * 明英宗被俘虏,明景帝即位,但是明景帝当上皇帝后乐疯了,竟然忘记把他老哥明英宗削为太上皇,
    * 也就是在这一个多月的时间内,中国竟然有两个皇帝!
    *
    */

    @SuppressWarnings("all")
    public class Emperor {
    private static int maxNumOfEmperor = 2; //最多只能有连个皇帝
    private static ArrayList emperorInfoList=new ArrayList(maxNumOfEmperor); //
    皇帝叫什么名字
    private static ArrayList emperorList=new ArrayList(maxNumOfEmperor); //装皇
    帝的列表;
    private static int countNumOfEmperor =0; //正在被人尊称的是那个皇帝
    //先把2个皇帝产生出来
    static{
    //把所有的皇帝都产生出来
    for(int i=0;i<maxNumOfEmperor;i++){
    emperorList.add(new Emperor("皇"+(i+1)+"帝"));
    }
    }
    //就这么多皇帝了,不允许再推举一个皇帝(new 一个皇帝)
    private Emperor(){
    //世俗和道德约束你,目的就是不让你产生第二个皇帝
    }
    private Emperor(String info){
    emperorInfoList.add(info);
    }
    public static Emperor getInstance(){
    Random random = new Random();
    countNumOfEmperor = random.nextInt(maxNumOfEmperor); //随机拉出一个皇帝,
    只要是个精神领袖就成
    return (Emperor)emperorList.get(countNumOfEmperor);
    }
    //皇帝叫什么名字呀
    public static void emperorInfo(){
    System.out.println(emperorInfoList.get(countNumOfEmperor));
    }
    }
    那大臣是比较悲惨了,两个皇帝呀,两个老子呀,怎么拜呀,不管了,只要是个皇帝就成:
    package com.cbf4life.singleton2;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 大臣们悲惨了,一个皇帝都伺候不过来了,现在还来了两个个皇帝
    * TND,不管了,找到个皇帝,磕头,请按就成了!
    */
    @SuppressWarnings("all")
    public class Minister {
    /**
    * @param args
    */
    public static void main(String[] args) {
    int ministerNum =10; //10个大臣
    for(int i=0;i<ministerNum;i++){
    Emperor emperor = Emperor.getInstance();
    System.out.print("第"+(i+1)+"个大臣参拜的是: ");
    emperor.emperorInfo();
    }
    }
    }
    那各位看官就可能会不屑了:有的大臣可是有骨气,只拜一个真神,你怎么处理?这个问题太简单,
    懒的详细回答你,getInstance(param)是不是就解决了这个问题?! 自己思考,太 Easy 了。
     

     

    第5 章工厂方法模式【Factory Method Pattern】
    女娲补天的故事大家都听说过吧,今天不说这个,说女娲创造人的故事,可不是“造人”的工作,这
    个词被现代人滥用了。这个故事是说,女娲在补了天后,下到凡间一看,哇塞,风景太优美了,天空是湛
    蓝的,水是清澈的,空气是清新的,太美丽了,然后就待时间长了就有点寂寞了,没有动物,这些看的到
    都是静态的东西呀,怎么办?
    别忘了是神仙呀,没有办不到的事情,于是女娲就架起了八卦炉(技术术语:建立工厂)开始创建人,
    具体过程是这样的:先是泥巴捏,然后放八卦炉里烤,再扔到地上成长,但是意外总是会产生的:
    第一次烤泥人,兹兹兹兹~~,感觉应该熟了,往地上一扔,biu~,一个白人诞生了,没烤熟!
    第二次烤泥人,兹兹兹兹兹兹兹兹~~,上次都没烤熟,这次多烤会儿,往地上一扔,嘿,熟过头了,
    黑人哪!
    第三次烤泥人,兹~兹~兹~,一边烤一边看着,嘿,正正好,Perfect!优品,黄色人类!【备注:RB 人
    不属此列】
    这个过程还是比较有意思的,先看看类图:(之前在论坛上有兄弟建议加类图和源文件,以后的模式都
    会加上去,之前的会一个一个的补充,目的是让大家看着舒服,看着愉悦,看着就想要,就像是看色情小
    说一样,目标,目标而已,能不能实现就看大家给我的信心了)
    那这个过程我们就用程序来表现,首先定义一个人类的总称:

    package com.cbf4life;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 定义一个人类的统称
    */
    public interface Human {
    //首先定义什么是人类
    //人是愉快的,会笑的,本来是想用smile表示,想了一下laugh更合适,好长时间没有大笑了;
    public void laugh();
    //人类还会哭,代表痛苦
    public void cry();
    //人类会说话
    public void talk();
    }
    然后定义具体的人类:
    package com.cbf4life;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 黄色人类,这个翻译的不准确,将就点吧
    */
    public class YellowHuman implements Human {
    public void cry() {
    System.out.println("黄色人类会哭");
    }
    public void laugh() {
    System.out.println("黄色人类会大笑,幸福呀! ");
    }
    public void talk() {
    System.out.println("黄色人类会说话,一般说的都是双字节");

    }
    }
    白色人类:
    package com.cbf4life;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 白色人类
    */
    public class WhiteHuman implements Human {
    public void cry() {
    System.out.println("白色人类会哭");
    }
    public void laugh() {
    System.out.println("白色人类会大笑,侵略的笑声");
    }
    public void talk() {
    System.out.println("白色人类会说话,一般都是但是单字节! ");
    }
    }
    黑色人类:
    package com.cbf4life;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 黑色人类,记得中学学英语,老师说black man是侮辱人的意思,不懂,没跟老外说话
    */
    public class BlackHuman implements Human {
    public void cry() {
    System.out.println("黑人会哭");

    }
    public void laugh() {
    System.out.println("黑人会笑");
    }
    public void talk() {
    System.out.println("黑人可以说话,一般人听不懂");
    }
    }
    人类也定义完毕了,那我们把八卦炉定义出来:
    package com.cbf4life;
    import java.util.List;
    import java.util.Random;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 今天讲女娲造人的故事,这个故事梗概是这样的:
    * 很久很久以前,盘古开辟了天地,用身躯造出日月星辰、山川草木,天地一片繁华
    * One day,女娲下界走了一遭,哎!太寂寞,太孤独了,没个会笑的、会哭的、会说话的东东
    * 那怎么办呢?不用愁,女娲,神仙呀,造出来呀,然后捏泥巴,放八卦炉(后来这个成了太白金星的宝
    贝)中烤,于是就有了人:
    * 我们把这个生产人的过程用Java程序表现出来:
    */
    public class HumanFactory {
    //定一个烤箱,泥巴塞进去,人就出来,这个太先进了
    public static Human createHuman(Class c){
    Human human=null; //定义一个类型的人类
    try {
    human = (Human)Class.forName(c.getName()).newInstance(); //产生一个
    人类
    } catch (InstantiationException e) {//你要是不说个人类颜色的话,没法烤,要白的
    黑,你说话了才好烤
    System.out.println("必须指定人类的颜色");
    } catch (IllegalAccessException e) { //定义的人类有问题,那就烤不出来了,这是...

    System.out.println("人类定义错误! ");
    } catch (ClassNotFoundException e) { //你随便说个人类,我到哪里给你制造去?!
    System.out.println("混蛋,你指定的人类找不到! ");
    }
    return human;
    }
    }
    然后我们再把女娲声明出来:
    package com.cbf4life;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 首先定义女娲,这真是额的神呀
    */
    public class NvWa {
    public static void main(String[] args) {
    //女娲第一次造人,试验性质,少造点,火候不足,缺陷产品
    System.out.println("------------造出的第一批人是这样的:白人
    -----------------");
    Human whiteHuman = HumanFactory.createHuman(WhiteHuman.class);
    whiteHuman.cry();
    whiteHuman.laugh();
    whiteHuman.talk();
    //女娲第二次造人,火候加足点,然后又出了个次品,黑人
    System.out.println(" ------------造出的第二批人是这样的:黑人
    -----------------");
    Human blackHuman = HumanFactory.createHuman(BlackHuman.class);
    blackHuman.cry();
    blackHuman.laugh();
    blackHuman.talk();
    //第三批人了,这次火候掌握的正好,黄色人类(不写黄人,免得引起歧义), 备注: RB人不属
    于此列
    System.out.println(" ------------造出的第三批人是这样的:黄色人类
    -----------------");

    Human yellowHuman = HumanFactory.createHuman(YellowHuman.class);
    yellowHuman.cry();
    yellowHuman.laugh();
    yellowHuman.talk()
    }
    }
    这样这个世界就热闹起来了,人也有了,但是这样创建太累了,神仙也会累的,那怎么办?神仙就想
    了:我塞进去一团泥巴,随机出来一群人,管他是黑人、白人、黄人,只要是人就成(你看看,神仙都偷
    懒,何况是我们人),先修改类图:
    然后看我们的程序修改,先修改 HumanFactory.java,增加了 createHuman()方法:
    package com.cbf4life;
    import java.util.List;
    import java.util.Random;
    public class HumanFactory {
    //定一个烤箱,泥巴塞进去,人就出来,这个太先进了
    public static Human createHuman(Class c){
    Human human=null; //定义一个类型的人类

    try {
    human = (Human)Class.forName(c.getName()).newInstance(); //产生一个
    人类
    } catch (InstantiationException e) {//你要是不说个人类颜色的话,没法烤,要白的
    黑,你说话了才好烤
    System.out.println("必须指定人类的颜色");
    } catch (IllegalAccessException e) { //定义的人类有问题,那就烤不出来了,这是...
    System.out.println("人类定义错误! ");
    } catch (ClassNotFoundException e) { //你随便说个人类,我到哪里给你制造去?!
    System.out.println("混蛋,你指定的人类找不到! ");
    }
    return human;
    }
    //女娲生气了,把一团泥巴塞到八卦炉,哎产生啥人类就啥人类
    public static Human createHuman(){
    Human human=null; //定义一个类型的人类
    //首先是获得有多少个实现类,多少个人类
    List<Class> concreteHumanList =
    ClassUtils.getAllClassByInterface(Human.class); //定义了多少人类
    //八卦炉自己开始想烧出什么人就什么人
    Random random = new Random();
    int rand = random.nextInt(concreteHumanList.size());
    human = createHuman(concreteHumanList.get(rand));
    return human;
    }
    }
    然后看女娲是如何做的:
    package com.cbf4life;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    * 首先定义女娲,这真是额的神呀
    */

    public class NvWa {
    public static void main(String[] args) {
    //女娲第一次造人,试验性质,少造点,火候不足,缺陷产品
    System.out.println("------------造出的第一批人是这样的:白人
    -----------------");
    Human whiteHuman = HumanFactory.createHuman(WhiteHuman.class);
    whiteHuman.cry();
    whiteHuman.laugh();
    whiteHuman.talk();
    //女娲第二次造人,火候加足点,然后又出了个次品,黑人
    System.out.println(" ------------造出的第二批人是这样的:黑人
    -----------------");
    Human blackHuman = HumanFactory.createHuman(BlackHuman.class);
    blackHuman.cry();
    blackHuman.laugh();
    blackHuman.talk();
    //第三批人了,这次火候掌握的正好,黄色人类(不写黄人,免得引起歧义), 备注: RB人不属
    于此列
    System.out.println(" ------------造出的第三批人是这样的:黄色人类
    -----------------");
    Human yellowHuman = HumanFactory.createHuman(YellowHuman.class);
    yellowHuman.cry();
    yellowHuman.laugh();
    yellowHuman.talk();
    //女娲烦躁了,爱是啥人类就是啥人类,烧吧
    for(int i=0;i<10000000000;i++){
    System.out.println(" ------------随机产生人类了-----------------" +
    i);
    Human human = HumanFactory.createHuman();
    human.cry();
    human.laugh();
    human.talk();
    }
    }
    }
    哇,这个世界热闹了!,不过还没有完毕,这个程序你跑不起来,还要有这个类:
    package com.cbf4life;
    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.Enumeration;
    import java.util.List;
    /**
    * @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
    * all.
    *
    */
    @SuppressWarnings("all")
    public class ClassUtils {
    //给一个接口,返回这个接口的所有实现类
    public static List<Class> getAllClassByInterface(Class c){
    List<Class> returnClassList = new ArrayList<Class>(); //返回结果
    //如果不是一个接口,则不做处理
    if(c.isInterface()){
    String packageName = c.getPackage().getName(); //获得当前的包名
    try {
    List<Class> allClass = getClasses(packageName); //获得当前包下以
    及子包下的所有类
    //判断是否是同一个接口
    for(int i=0;i<allClass.size();i++){
    if(c.isAssignableFrom(allClass.get(i))){ //判断是不是一个接口
    if(!c.equals(allClass.get(i))){ //本身不加进去
    returnClassList.add(allClass.get(i));
    }
    }
    }
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    return returnClassList;
    }
    //从一个包中查找出所有的类,在jar包中不能查找
    private static List<Class> getClasses(String packageName)
    throws ClassNotFoundException, IOException {
    ClassLoader classLoader = Thread.currentThread()
    .getContextClassLoader();
    String path = packageName.replace('.', '/');
    Enumeration<URL> resources = classLoader.getResources(path);
    List<File> dirs = new ArrayList<File>();
    while (resources.hasMoreElements()) {
    URL resource = resources.nextElement();
    dirs.add(new File(resource.getFile()));
    }
    ArrayList<Class> classes = new ArrayList<Class>();
    for (File directory : dirs) {
    classes.addAll(findClasses(directory, packageName));
    }
    return classes;
    }
    private static List<Class> findClasses(File directory, String packageName)
    throws ClassNotFoundException {
    List<Class> classes = new ArrayList<Class>();
    if (!directory.exists()) {
    return classes;
    }
    File[] files = directory.listFiles();
    for (File file : files) {
    if (file.isDirectory()) {
    assert !file.getName().contains(".");
    classes.addAll(findClasses(file, packageName + "." +
    file.getName()));
    } else if (file.getName().endsWith(".class")) {
    classes.add(Class.forName(packageName + '.' +
    file.getName().substring(0, file.getName().length() - 6)));
    }
    }
    return classes;
    }
    }
    告诉你了,这个 ClassUtils 可是个宝,用处可大了去了,可以由一个接口查找到所有的实现类,也可
    以由父类查找到所有的子类,这个要自己修改一下,动脑筋想下,简单的很!完整的类图如下:
    我们来总结一下,特别是增加了 createHuman()后,是不是这个工厂的扩展性更好了?你看你要再加一
    个人类,只要你继续集成 Human 接口成了,然后啥都不用修改就可以生产了,具体产多少,那要八卦炉说
    了算,简单工厂模式就是这么简单,那我们再引入一个问题:人是有性别的呀,有男有女,你这怎么没区
    别,别急,这个且听下回分解!
    工厂方法模式还有一个非常重要的应用,就是延迟始化(Lazy initialization),什么是延迟始化呢?
    一个对象初始化完毕后就不释放,等到再次用到得就不用再次初始化了,直接从内存过中拿到就可以了,
    怎么实现呢,很简单,看例子:
    package com.cbf4life.advance;
    import java.util.HashMap;
    /**
    * @author cbf4Life cbf4life@126.com
    * I'm glad to share my knowledge with you all.
    */
    @SuppressWarnings("all")
    public class HumanFactory {
    //定义一个MAP,初始化过的Human对象都放在这里
    private static HashMap<String,Human> humans = new HashMap<String,Human>();
    //定一个烤箱,泥巴塞进去,人就出来,这个太先进了
    public static Human createHuman(Class c){
    Human human=null; //定义一个类型的人类
    try {
    //如果MAP中有,则直接从取出,不用初始化了
    if(humans.containsKey(c.getSimpleName())){
    human = humans.get(c.getSimpleName());
    }else{
    human = (Human)Class.forName(c.getName()).newInstance();
    //放到MAP
    humans.put(c.getSimpleName(), human);
    }
    } catch (InstantiationException e) {//你要是不说个人类颜色的话,没法烤,要白的
    黑,你说话了才好烤
    System.out.println("必须指定人类的颜色");
    } catch (IllegalAccessException e) { //一定定义的人类有问题,那就烤不出来了,
    这是...
    System.out.println("人类定义错误! ");
    } catch (ClassNotFoundException e) { //你随便说个人类,我到哪里给你制造去?!
    System.out.println("混蛋,你指定的人类找不到! ");
    }
    return human;
    }
    }
    很简单,就加上了黄色那部分的代码,这个在类初始化很消耗资源的情况比较实用,比如你要连接硬
    件,或者是为了初始化一个类需要准备比较多条件(参数),通过这种方式可以很好的减少项目的复杂程度。

  • 相关阅读:
    javaBean的理解
    配置tomcat8数据源(采用局部数据源方式)
    windows下apache报os 10048错误
    Windows下Apache的下载安装启动停止
    java通过数据库连接池链接oracle
    java连接oracle数据库
    eclipse配置svn方法
    JAVA多线程中start方法与run方法区别
    java程序在没有java环境的电脑上执行的方法(关键词jar,exe)
    js监听不到组合键
  • 原文地址:https://www.cnblogs.com/Jansens520/p/6393170.html
Copyright © 2011-2022 走看看