精华内容
下载资源
问答
  • 关于青春的英语小品剧本 - 英语剧本大全 - 搞笑小品剧本 - 中国国际剧本网
    2021-06-30 05:27:54

    Scene I

    (Anita, Kevin, Ken, Jason, Steven, and Rita are all Tunghai University students. They are good friends. One day, Ken and Jason meet on the way to the classroom.)

    Ken: Why are you late? And, you just missed the last class. The teacher gave us the main topics for the mid-term examination.

    Jason: Oh, shoot! I just missed it. Would you lend me your notes so I can make a copy?

    Ken: Sure if you give me a good reason why you missed the class. You promised me that you would be in class on time today.

    Jason: Believe me, I would like to keep my word. The problem is that I have the “Business Management” test today and I was up studying for it till three o’clock this morning. Then I fell asleep and woke up at ten o’clock this morning.

    Ken: You studied until three o’clock this morning? Why? What did you do yesterday afternoon? I know you were free from four o’clock on yesterday.

    Jason: Well, I met one of my very old friends on line and we just talked too long…

    Ken: For God’s sake! Don’t you care about next week’s mid-term examination?

    --------------------------------------------------------------------------------

    Scene II

    (Anita, Steven and Kevin are talking to one another in front of a classroom. And, Anita is trying to prevent Steven and Kevin from cutting the next class.)

    Anita: Hey, we’ll have the “Business Management” class in a few minutes. Where are you going? Don’t tell me that you are going to argue with Jason.

    Steven: I will do anything for my good friend. Of course I am going to argue with the guy who gave my good friend a hard time.

    Anita: You always like to get involved in someone else’s business. You’ll get yourself in trouble. Don’t you know it? ...

    Kevin: Anita, don’t be upset with him. He will not listen to you. Just leave him alone. By the way, I am still waiting for your decision. Are you coming with me to the concert tomorrow?

    Anita: Oh, I am sorry that I almost forgot it. What time tomorrow?

    Kevin: Two o’clock. I cannot wait to see my adorable superstar – Jolin. Oh, how wonderful!

    Anita: wait a minute. We have Calculus class tomorrow afternoon. Are you out of your mind?

    Kevin: Well, I’m not. Yet I think we can just copy the notes from someone else.

    Anita: No, this is a very important class. And you would never understand it without listening to the lecture.

    Kevin: To me it makes no difference. Even if I were in the class I would never understand what the teacher is talking about. Besides, who likes to look at the old baldhead?

    更多相关内容
  • 继2014年「呸」《PLAY》掀起全球话题热度并创华语流行音乐经典模范后,亚洲流行天后Jolin蔡依林睽违乐坛四年的新专辑《UGLY BEAUTY》将于12月压轴登场!... Jolin透过主题《UGLY BEAUTY》的“情绪”与...

    继2014年「呸」《PLAY》掀起全球话题热度并创华语流行音乐经典模范后,亚洲流行天后Jolin蔡依林睽违乐坛四年的新专辑《UGLY BEAUTY》将于12月压轴登场!上一张专辑从自身观点去探讨社会上各种表面现象,这次新作品回归内心层面,Jolin从不断地自问自答、自我探索内心的过程中,发现到正视并拥抱自己的阴暗丑陋面,得到的反馈是美好的! Jolin透过主题《UGLY BEAUTY》的“情绪”与“欲望”探讨人类的“感”、“观”,打破世俗对于美与丑的二分法并重新定义!

    20年能量爆发 蔡依林全新专辑《UGLY BEAUTY》12月5日发布

    最多创作的Jolin:自组音乐写作营参与创作 2年制作远征斯德哥尔摩

    Jolin打破过去专辑制作的收歌方式,以全新的创作模式自组音乐写作营,亲自参与音乐人集体创作的方式,完成新专辑《UGLY BEAUTY》的歌曲。 Jolin亲自“泡”录音室参与创作的集体创作,除了在台北还到曼谷,甚至远征斯德哥尔摩,分别透过这几个城市音乐写作营的音乐人撞击合作,动员近百位跨国音乐人,体验到与世界各地的音乐人关在录音室一周,一起脑力激荡的有趣过程,不但激发出Jolin自我潜能,更让Jolin的创作力大爆发,新专辑一口气参与了六首歌的创作作品。新专辑《UGLY BEAUTY》不仅将会听到Jolin首次尝试的创作模式,更将犹如大满贯地听到“创作力大爆发”及“最具Jolin 创作力”的一张专辑! Jolin表示:“自由的创作过程中,我探索出让自己感动的声音,而且跟不同的创作营合作,给我很大的推进力,一起做音乐讨论、用不同的语言方式去表达你想要什么,除了蛮过瘾、蛮好玩之外,作品应该会让大家听了跟我一样很有感觉!”

    最诚实的Jolin:将自己打掉重炼11首新歌

    这两年对心理学有兴趣的Jolin,透过心理学大师荣格的书,开始挖掘内心世界及探索自己,Jolin表示:“以前是没有做到一百分,我就会很自责,我觉得我是一个不值得一提的人。”而这个摸索过程却意外发现到曾经那个总想要考一百分、证明自己“我可以”的Jolin,一直忘记内在阴性的力量而忘记如何好好爱自己;透过这样的挖掘过程,于是联想到《UGLY BEAUTY》主题为新专辑催生,Jolin表示:“对我来说面对自己UGLY的一面就是情绪的一环,当你开始面对它之后,获得的反馈是很美好的、更多的爱与同理心,你会很了解你自己当初作这件事情的决定,就不太容易去批判自己及批判别人!”新专辑的诞生过程Jolin透过不断的探讨、认识自己,专辑制作过程历经多次的“打掉重炼”,新专辑完整纪录、呈现Jolin这段“认识自己”的旅程“感”“观”,也是Jolin歌唱生涯中最“诚实”的一张专辑!

    最实验的jolin:专辑试验多种不同曲风 忠于音乐的直觉

    新专辑汇集来自世界各地音乐的创新作品,及主题《UGLY BEAUTY》多元化的探讨内容,新专辑加入实验性的成份、曲风不同以往。Jolin秉持“忠于音乐”的直觉,势必将带给华语流行乐坛更多的冲击力、听觉的新感官!勇于接受挑战的Jolin表示:“我就是想试!”专辑制作过程中Jolin喜欢自问自答,也非常好奇、察觉女性力量及影响力,原本新专辑想探讨“什么是女人”,投入的过程中发现自己才是最佳的“实验对象”,便开始一股脑地挖出内心世界的东西去探讨,发现“情绪”正是影响自己及他人的关键点,因此常自问自答“自己是什么样的女人”;Jolin表示:“一直觉得我在女性这个角色少了一点东西,虽然大家看我外表像公主样子,但我一直觉得内心是个男人!这样的冲突点像是漩涡一样,让我不由自主地想要去研究。 ”

    时尚圈当红摄影师Zhong Lin 新时代十大影响力造型师Yii打造11款怪美Jolin

    配合新专辑十一首歌曲主题,特别邀请时尚圈当红摄影师ZHONG LIN及曾被Gucci点名合作、被全球时尚界评选为新时代十大影响力人物之一的名造型师yii,打造11套怪美风格的《UGLY BEAUTY》造型。首波公布的预购视觉,Jolin戴上造型夸张的“真理之口”红唇饰品、佐以双手诡异的姿势及双眼无辜神情,让整张海报的视觉非常具有冲击性,也呼应这次专辑打破世俗美丑观念的概念主题。值得一提的是,这副“真理之口”大有来头,出自毕业于安特卫普皇家艺术学院的华人之光设计师 Shuting Qiu打造的作品。 Jolin强调这张视觉照片的重点在于脆弱的眼神! Jolin解释道:“真理之口,象征着很多想讲却讲不出来的言语,脆弱的眼神代表我理解你的心情,因为我也曾经是这样。” Jolin挑战连续两天、超过24小时non stop的拍摄任务,在重视氛围感及即兴演出的摄影师ZHONG LIN的镜头要求下,短时间穿梭在11个场景及11种角色设定中,Jolin表示: “快人格分裂了,但演得很爽!”11款“怪”、“美”的Jolin全新视觉,势必将引起歌迷的骚动。

    20年能量爆发 蔡依林全新专辑《UGLY BEAUTY》12月5日发布

    20年能量爆发 蔡依林全新专辑《UGLY BEAUTY》12月5日发布

    展开全文
  • Unity+GitHub多人协作开发

    千次阅读 2021-08-09 16:44:57
    我借助了VS Code,用VS Code打开仓库的文件夹,然后你就会惊奇的发现,产生冲突的文件都用紫色标记出来了(在我这个暗主题是紫色的),点开冲突文件以后更是发现冲突的部分还高亮显示出来了,上面还有四个选项: ...

    前期准备

    1. 首先我用我的GitHub账号,新建了一个仓库(repository),之后用来存放我们的Unity项目。需要合作者的账号,添加为该项目的合作者(collaborators)。

      GitHub官网:https://github.com

      在自己这边点击了Add collaborator以后,Github会给对方发一份邮件到注册的那个邮箱,对方要在邮件中确认以后才算是添加成功。

    2. 配置SSH

      (1)安装git客户端。网址:https://git-scm.com/download/win

      一直点next按默认的安装就行。

    版本控制

    首先我要上传了最新版本的Unity项目到github上。

    上传步骤:

    1. 项目文件夹下进入Git Bash
    2. 输入git init,将项目初始化为仓库
    3. 输入git remote add origin git@github.com:Jolinbaby/AIAD-Experiment.git, 建立本地仓库和远程仓库的连接
    4. 导入一个.gitignore文件,用来设置Unity模板(就是决定哪些文件夹是需要上传的)
    5. 输入git status,红色部分就是要上传的文件
    6. 输入git add .
    7. 输入git commit -m "你的备注信息"
    8. 输入git push -u origin master
    9. 刷新github上的页面,提交完成

    项目上传完了,接下来团队协作的时候,如何运用git来进行多人协作呢?

    前提:已经添加为合作者

    之后每次要对项目进行更新,按一下步骤操作即可:

    1. 先登录

      git config --global user.name "你的名字"

      git config --global user.email "你的邮箱"

    2. 配置ssh

      教程:https://blog.csdn.net/kaimo313/article/details/107307266

    3. 在自己的PC上clone下来该项目

      (1)仓库的ssh地址:git@github.com:Jolinbaby/AIAD.git

      注意:gitbash中的粘贴键不是ctrl+v,

      复制: CTRL+INSERT
      粘贴: SHIFT+INSERT

      (2)首先,在你要放项目文件夹的位置鼠标右键,选择git bash here

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jbHnFLjn-1628498669211)(C:\Users\12921\AppData\Roaming\Typora\typora-user-images\image-20210807231453772.png)]

    ​ (3)输入git clone git@github.com:Jolinbaby/AIAD.git, 将github上的项目克隆到本地

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SeKhksUX-1628498669214)(C:\Users\12921\AppData\Roaming\Typora\typora-user-images\image-20210807231518439.png)]

    1. 用Unity打开项目,即可进行修改
    2. 修改完后,更新最新版本到github上的远程仓库
      1. 在项目文件夹下右键,进入Git Bash
      2. 输入git status 查看修改是否已被记录
      3. 输入git add .(注意点点前面有空格) 将项目保存至暂存区
      4. 输入git commit -m"ourAR2.0 By:Jolin"(引号内输入备注信息,比如版本号和修改者姓名)
      5. 输入git push origin master即可push最新版本至远程仓库(有可能需要验证用户名和密码)
    3. 若操作正确,刷新后github上即更新内容。

    这样,在github上就可以清晰地看出每个文件的最新修改情况(只会更新有修改的文件,没有修改的地方不会动),还可以回溯到之前的版本。(所以备注的时候一定要标明版本号或者修改的时间or第几次修改,便于查看)

    参考:https://blog.csdn.net/fanxiangru999/article/details/79464211?ops_request_misc=&request_id=&biz_id=102&utm_term=github%E5%A6%82%E4%BD%95%E5%8D%8F%E4%BD%9C&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-6-.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187

    解释说明

    参考:https://blog.csdn.net/yzr1216/article/details/81114560?ops_request_misc=&request_id=&biz_id=102&utm_term=github%E5%A6%82%E4%BD%95%E5%8D%8F%E4%BD%9C&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-2-.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187

    • 项目已经是所有人可见了,为什么要添加合作者?

    除了项目的所有者外,其他人仅是“可见”,可以把项目保存到自己的本地却无法将自己的修改push上去,因此需要设置为合作者,才可以共同修改项目。

    • 合并冲突
      多人协作的重头戏就在这里了。

    冲突怎么产生的?

    Git其实是有自动合并功能的,比如A修改了a文件,B修改了b文件,这两个修改互不相干,是可以自动合并的。但是A和B同时修改a文件,两人修改的地方不相同的话有些时候也是能自动合并,如果连修改的地方都相同,那程序就无能为力了,只能够由人来确定到底应该保留谁的修改,这就是冲突。

    怎么知道有没有冲突?

    看见出现conflict这个词就是有冲突了。没截图,遇到再补上吧。

    怎么解决冲突?(遇到冲突的时候再细看吧)
    找到产生冲突的文件修改即可。

    在本地仓库根目录中调出Git Bash界面,输入命令git status,就可以看到哪些文件是被同时修改了。(图略,待补)

    至于修改方法,Git Bash那种vim方式我用不惯。我借助了VS Code,用VS Code打开仓库的文件夹,然后你就会惊奇的发现,产生冲突的文件都用紫色标记出来了(在我这个暗主题是紫色的),点开冲突文件以后更是发现冲突的部分还高亮显示出来了,上面还有四个选项:

    “保留当前更改”:字面意思
    “保留传入更改”:字面意思(PS:当前更改和传入更改要保留哪个是不固定的,要看你实际情况,比如有a和b分支,a合并到b,a就是传入,b就是当前;b合并到a,b就是传入,a就是当前,最后合并的结果是一样的)
    “保留双方更改”:有些情况双方的修改也要保留
    “还有个忘记了”:
    (图略,待补)

    PS:一开始用VS Code打开冲突文件的瞬间我真的被震惊了,原来VS Code对Git的支持这么友好,有那么一瞬间我想一直遇到冲突2333
    ————————————————
    原文链接:https://blog.csdn.net/yzr1216/article/details/81114560

    Git常用命令

    img

    展开全文
  • 【笔记】设计模式

    2020-02-07 16:04:52
    设计模式(Design Pattern) 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。 一、六大原则 ...

    本文整理自 史上最全设计模式导学目录(完整版)

    参考:https://blog.csdn.net/mnb65482/article/details/80458571


    文章目录

    设计模式(Design Pattern)

    设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。

    一、六大原则

    1.单一职责原则(Single-Resposibility Principle)

    高内聚
    如果一个类承担的职责过多,那么这些职责就会相互依赖,一个职责的变化可能会影响另一个职责的履行。

    2. 开闭原则(Open-Closed principle)

    对扩展开放,对修改关闭
    需求变更时,不必改动源代码,就能扩展它的行为,通常通过抽象类或接口来实现。

    3.里式替换原则(Liskov-Substituion Principle)

    子类型必须能够替换掉它们的基类型。正是子类型的可替换性,才使得使用基类型模块无需修改就可扩充。

    4.依赖倒置原则(Dependecy-Inversion Principle)

    抽象不应依赖于细节,细节应该依赖于抽象。
    先有抽象程度比较高的实体,再有才是更加细节化的实体。

    5.接口隔离原则(Interface-Segregation Principle)

    多个专用接口优于一个单一的通用接口,本质上也是高内聚。

    6.良性依赖原则

    不会在实际中造成危害的依赖关系,都是良性依赖。

    二、分类

    设计模式共23种,分为三大类:

    三、创建型

    1.工厂方法模式(factory)

    1.1 定义

    定义一个用于创建对象的接口,让子类决定将哪一个类实例化。

    1.2例子

    需求

    日志记录器的设计:
    该记录器可以通过多种途径保存系统的运行日志,如通过文件记录或数据库记录,用户可以通过修改配置文件灵活地更换日志记录方式。在设计各类日志记录器时,Sunny公司的开发人员发现需要对日志记录器进行一些初始化工作,初始化参数的设置过程较为复杂,而且某些参数的设置有严格的先后次序,否则可能会发生记录失败。
    如何封装记录器的初始化过程并保证多种记录器切换的灵活性是Sunny公司开发人员面临的一个难题。

    设计

    在这里插入图片描述

    实现
    public interface Logger {
         void writeLog();
    }
    
    public class FileLogger implements Logger {
    
        public FileLogger() {
            System.out.println("FileLogger");
        }
    
        @Override
        public void writeLog() {
            System.out.println("FileLogger.writeLog()");
        }
    
    }
    
    public class DatabaseLogger implements Logger {
    
        public DatabaseLogger() {
            System.out.println("DatabaseLogger");
        }
    
        @Override
        public void writeLog() {
            System.out.println("DatabaseLogger.writeLog()");
        }
    
    }
    
    //日志记录器工厂
    public interface LoggerFactory {
    
        Logger createLogger();
    
    }
    
    public class FileLoggerFactory implements LoggerFactory {
    
        @Override
        public Logger createLogger() {
            FileLogger logger = new FileLogger();
            return logger;
        }
    
    }
    
    public class DatabaseLoggerFactory implements LoggerFactory {
    
        @Override
        public Logger createLogger() {
            Logger logger = new DatabaseLogger();
            return logger;
        }
    
    }
    
    测试
    public class Test {
    
        /**
         * LoggerFactory的具体类型,可以写在配置文件中,灵活使用
         * @param args
         */
        public static void main(String[] args) {
            LoggerFactory factory=new DatabaseLoggerFactory();
            Logger logger=factory.createLogger();
            logger.writeLog();
        }
    }
    

    1.3优缺点

    优点:
    • 具体实现被隐藏,用户无需关心创建细节
    • 具体工厂类都具有同一抽象父类
    • 使用工厂方法模式的另一个优点是在系统中加入新产品时,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
    缺点:
    • 在添加新产品较多时,新增类较多,复杂性较高
    • 抽象层较多,增加理解难度

    2.抽象工厂模式(Abstract Factory)

    2.1 定义

    提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
    在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为“开闭原则”的倾斜性。

    2.2例子

    需求

    Sunny软件公司欲开发一套界面皮肤库,可以对Java桌面软件进行界面美化。为了保护版权,该皮肤库源代码不打算公开,而只向用户提供已打包为jar文件的class字节码文件。用户在使用时可以通过菜单来选择皮肤,不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等界面元素,其结构示意图如图1所示:

    图1 界面皮肤库结构示意图
    该皮肤库需要具备良好的灵活性和可扩展性,用户可以自由选择不同的皮肤,开发人员可以在不修改既有代码的基础上增加新的皮肤。

    设计

    在这里插入图片描述

    实现
    public interface Button {
    
         void display();
    
    }
    
    public class SpringButton implements Button {
    
        public void display() {
            System.out.println("SpringButton.display()");
        }
    
    }
    
    public class SummerButton implements Button {
    
        public void display() {
            System.out.println("SummerButton.display()");
        }
    
    }
    
    public interface TextField {
    
        void display();
    
    }
    
    public class SpringTextField implements TextField {
    
        public void display() {
            System.out.println("SpringTextField.display()");
        }
    
    }
    
    public class SummerTextField implements TextField {
    
        public void display() {
            System.out.println("SummerTextField.display()");
        }
    
    }
    
    //抽象工厂
    public interface AbstractFactory {
    
        Button createButton();
    
        TextField createTextField();
    
    }
    public class SpringFactory implements AbstractFactory {
    
        @Override
        public Button createButton() {
            return new SpringButton();
        }
    
        @Override
        public TextField createTextField() {
            return new SpringTextField();
        }
    
    }
    
    public class SummerFactory implements AbstractFactory {
    
        @Override
        public Button createButton() {
            return new SpringButton();
        }
    
        @Override
        public TextField createTextField() {
            return new SpringTextField();
        }
    
    }
    
    测试
    public class Test {
    
        /**
         * AbstractFactory的具体类型,可以写在配置文件中,灵活使用
         * @param args
         */
        public static void main(String[] args) {
            AbstractFactory factory = new SpringFactory();
            Button button = factory.createButton();
            button.display();
            TextField textField = factory.createTextField();
            textField.display();
        }
    
    }
    

    2.3优缺点

    优点:
    • 具体实现被隐藏,用户无需关心创建细节
    • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
    • 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。
    缺点:
    • 增加新的产品等级结构很麻烦

    在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为“开闭原则”的倾斜性。

    3.单例模式(Singleton)

    3.1定义

    确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。

    3.2实现核心

    构造方法私有,静态变量保存

    3.3饿汉式 线程安全

    类初始化时直接创建对象,占用内存,无论是否使用

    1.直接实例化饿汉式(简洁直观)

    public class Singleton1 {
        public static final Singleton1 INSTANCE = new Singleton1();
    
        private Singleton1() {
        }
    }
    

    2.枚举式(最简洁)

    用的时候加载,常量只有一份

    public enum Singleton2 {
        INSTANCE
    }
    

    3.静态代码块饿汉式(适合复杂实例化)

    public class Singleton3 {
        public static final Singleton3 INSTANCE;
        private String info;
    
        private Singleton3(String info) {
            this.info = info;
        }
    
        static {
            try {
                Properties p = new Properties();
                p.load(Singleton3.class.getClassLoader().getResourceAsStream("prop.properties"));
                INSTANCE = new Singleton3(p.getProperty("info"));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    

    3.4懒汉式(延迟加载)

    1.简单懒汉 线程不安全

    public class Singleton4 {
        private static Singleton4 instance;
    
        private Singleton4() {
        }
    
        public static Singleton4 getInstance() {
            if (instance == null) {
                instance = new Singleton4();
            }
            return instance;
        }
    }
    
    

    缺点:在多线程环境中,不能保证单例的状态,instance为变量,在并发的时候不能保证是单例
    测试、以下代码线程不安全:

    public class Singleton4 {
        private static Singleton4 instance;
    
        private Singleton4() {
        }
    
        public static Singleton4 getInstance() {
            if (instance == null) {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                instance = new Singleton4();
            }
            return instance;
        }
    }
    
    

    2.DCL(Double checked locking)双检查锁机制 线程安全

    public class Singleton5 {
        private volatile static Singleton5 instance;
    
        private Singleton5() {
        }
    
        public static Singleton5 getInstance() {
            if (instance == null) {
                synchronized (Singleton5.class) {
                    if (instance == null) {
                        instance = new Singleton5();
                    }
                }
            }
            return instance;
        }
    }
    

    需要注意的是,如果使用双重检查锁定来实现懒汉式单例类,需要在静态成员变量instance之前增加修饰符volatile,被volatile修饰的成员变量可以确保多个线程都能够正确处理,且该代码只能在JDK 1.5及以上版本中才能正确执行。由于volatile关键字会屏蔽Java虚拟机所做的一些代码优化,可能会导致系统运行效率降低,因此即使使用双重检查锁定来实现单例模式也不是一种完美的实现方式。
    测试、以下代码线程安全:

    public class Singleton5 {
        private volatile static Singleton5 instance;
    
        private Singleton5() {
        }
    
        public static Singleton5 getInstance() {
            if (instance == null) {
                synchronized (Singleton5.class) {
                    if (instance == null) {
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        instance = new Singleton5();
                    }
                }
            }
            return instance;
        }
    }
    

    3.静态内部类形式 线程安全

    public class Singleton6 {
    
        private Singleton6() {
        }
    
        private static class Inner {
            private static final Singleton6 INSTANCE = new Singleton6();
        }
    
        public static Singleton6 getInstance() {
            return Inner.INSTANCE;
        }
    }
    

    静态内部类的优点是:外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化INSTANCE,故而不占内存。

    那么,静态内部类又是如何实现线程安全的呢?首先,我们先了解下类的加载时机。

    类加载时机:JAVA虚拟机在有且仅有的5种场景下会对类进行初始化。

    1. 遇到new、getstatic、setstatic或者invokestatic这4个字节码指令时,对应的java代码场景为:new一个关键字或者一个实例化对象时、读取或设置一个静态字段时(final修饰、已在编译期把结果放入常量池的除外)、调用一个类的静态方法时。
    2. 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没进行初始化,需要先调用其初始化方法进行初始化。
    3. 当初始化一个类时,如果其父类还未进行初始化,会先触发其父类的初始化。
    4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的类),虚拟机会先初始化这个类。
    5. 当使用JDK 1.7等动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

    这5种情况被称为是类的主动引用,注意,这里《虚拟机规范》中使用的限定词是"有且仅有",那么,除此之外的所有引用类都不会对类进行初始化,称为被动引用。静态内部类就属于被动引用的行列。

    3.5测试类

    public class TestSingleton {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            for (int i = 0; i < 2; i++) {
                Singleton1 singleton1 = Singleton1.INSTANCE;
                System.out.println("singleton1第" + i + "次:" + singleton1);
                Singleton2 singleton2 = Singleton2.INSTANCE;
                System.out.println("singleton2第" + i + "次:" + singleton2);
                Singleton3 singleton3 = Singleton3.INSTANCE;
                System.out.println("singleton3第" + i + "次:" + singleton3);
    
                Singleton6 singleton6 = Singleton6.getInstance();
                System.out.println("singleton6第" + i + "次:" + singleton6);
            }
    
            Callable<Singleton4> c = new Callable<Singleton4>() {
                @Override
                public Singleton4 call() throws Exception {
                    return Singleton4.getInstance();
                }
            };
            ExecutorService e = Executors.newFixedThreadPool(2);
            Future<Singleton4> f1 = e.submit(c);
            Future<Singleton4> f2 = e.submit(c);
            Singleton4 s41 = f1.get();
            Singleton4 s42 = f2.get();
            System.out.println("Singleton4结果:");
            System.out.println(s41 == s42);
            e.shutdown();
    
            Callable<Singleton5> c2 = new Callable<Singleton5>() {
                @Override
                public Singleton5 call() throws Exception {
                    return Singleton5.getInstance();
                }
            };
            ExecutorService e2 = Executors.newFixedThreadPool(2);
            Future<Singleton5> f3 = e2.submit(c2);
            Future<Singleton5> f4 = e2.submit(c2);
            Singleton5 s51 = f3.get();
            Singleton5 s52 = f4.get();
            System.out.println("Singleton5结果:");
            System.out.println(s51 == s52);
            e2.shutdown();
    
        }
    }
    

    console

    singleton1第0次:com.dyn.demo.springclouddemo.Singleton.Singleton1@3a71f4dd
    singleton2第0次:INSTANCE
    singleton3第0次:com.dyn.demo.springclouddemo.Singleton.Singleton3@85ede7b
    singleton6第0次:com.dyn.demo.springclouddemo.Singleton.Singleton6@5674cd4d
    singleton1第1次:com.dyn.demo.springclouddemo.Singleton.Singleton1@3a71f4dd
    singleton2第1次:INSTANCE
    singleton3第1次:com.dyn.demo.springclouddemo.Singleton.Singleton3@85ede7b
    singleton6第1次:com.dyn.demo.springclouddemo.Singleton.Singleton6@5674cd4d
    Singleton4结果:
    false
    Singleton5结果:
    true
    

    四、结构型

    1.适配器模式(Adapter)

    1.1 定义

    将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。
    适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。

    1.2对象适配器

    需求

    Sunny软件公司在很久以前曾开发了一个算法库,里面包含了一些常用的算法,例如排序算法和查找算法,在进行各类软件开发时经常需要重用该算法库中的算法。在为某学校开发教务管理系统时,开发人员发现需要对学生成绩进行排序和查找,该系统的设计人员已经开发了一个成绩操作接口ScoreOperation,在该接口中声明了排序方法sort(int[]) 和查找方法search(int[], int),为了提高排序和查找的效率,开发人员决定重用算法库中的快速排序算法类QuickSort和二分查找算法类BinarySearch,其中QuickSort的quickSort(int[])方法实现了快速排序,BinarySearch 的binarySearch (int[], int)方法实现了二分查找。

    由于某些原因,现在Sunny公司开发人员已经找不到该算法库的源代码,无法直接通过复制和粘贴操作来重用其中的代码;部分开发人员已经针对ScoreOperation接口编程,如果再要求对该接口进行修改或要求大家直接使用QuickSort类和BinarySearch类将导致大量代码需要修改。

    Sunny软件公司开发人员面对这个没有源码的算法库,遇到一个幸福而又烦恼的问题:如何在既不修改现有接口又不需要任何算法库代码的基础上能够实现算法库的重用?

    设计

    在这里插入图片描述

    实现
    //抽象成绩操作类:目标接口
    public interface ScoreOperation {
        public int[] sort(int array[]); //成绩排序
        public int search(int array[],int key); //成绩查找
    }
    
    // 适配器
    public class OperationAdapter implements ScoreOperation {
    
        BinarySearch binarySearch;
    
        QuickSort quickSort;
    
        public OperationAdapter() {
            binarySearch = new BinarySearch();
            quickSort = new QuickSort();
        }
    
        @Override
        public int[] sort(int[] array) {
            return quickSort.quickSort(array);
        }
    
        @Override
        public int search(int[] array, int key) {
            return binarySearch.binarySearch(array, key);
        }
    
    }
    
    //快速排序类:适配者
    public class QuickSort {
        public int[] quickSort(int array[]) {
            sort(array,0,array.length-1);
            return array;
        }
    
        public void sort(int array[],int p, int r) {
            int q=0;
            if(p<r) {
                q=partition(array,p,r);
                sort(array,p,q-1);
                sort(array,q+1,r);
            }
        }
    
        public int partition(int[] a, int p, int r) {
            int x=a[r];
            int j=p-1;
            for (int i=p;i<=r-1;i++) {
                if (a[i]<=x) {
                    j++;
                    swap(a,j,i);
                }
            }
            swap(a,j+1,r);
            return j+1;
        }
    
        public void swap(int[] a, int i, int j) {
            int t = a[i];
            a[i] = a[j];
            a[j] = t;
        }
    }
    
    //二分查找类:适配者
    public class BinarySearch {
        public int binarySearch(int array[],int key) {
            int low = 0;
            int high = array.length -1;
            while(low <= high) {
                int mid = (low + high) / 2;
                int midVal = array[mid];
                if(midVal < key) {
                    low = mid +1;
                }
                else if (midVal > key) {
                    high = mid -1;
                }
                else {
                    return 1; //找到元素返回1
                }
            }
            return -1;  //未找到元素返回-1
        }
    }
    
    测试
    public class Test {
    
        public static void main(String[] args) {
            ScoreOperation operation = new OperationAdapter();
            int[] scores = {84, 76, 50, 69, 90, 91, 88, 96}; //定义成绩数组
            for (int i : scores) {
                System.out.print(i + ",");
            }
            System.out.println();
            scores = operation.sort(scores);
            for (int i : scores) {
                System.out.print(i + ",");
            }
        }
    
    }
    

    1.3缺省适配器

    当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。

    设计

    在这里插入图片描述

    实现
    public interface ServiceInterface {
        void test1();
        void test2();
        void test3();
        void test4();
    }
    
    public abstract class AbstractServiceClass implements ServiceInterface {
    
        public void test1() {
        }
    
        public void test2() {
        }
    
        public void test3() {
        }
    
        public void test4() {
        }
    
    }
    
    public class ConcreteServiceClass extends AbstractServiceClass {
    
        public void test1() {
        }
    
    }
    

    1.4优缺点

    优点:
    • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。
    • 增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者的复用性,同一个适配者类可以在多个不同的系统中复用。
    • 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
    缺点:
    • 不能多继承,一次最多只能适配一个适配者类,不能同时适配多个适配者
    • 类适配器模式中的目标抽象类只能为接口,不能为类,其使用有一定的局限性。

    2.装饰器模式(Decorator)

    2.1 定义

    动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。

    2.2例子

    需求

    图形界面构件库的设计
    Sunny软件公司基于面向对象技术开发了一套图形界面构件库VisualComponent,该构件库提供了大量基本构件,如窗体、文本框、列表框等,由于在使用该构件库时,用户经常要求定制一些特效显示效果,如带滚动条的窗体、带黑色边框的文本框、既带滚动条又带黑色边框的列表框等等,因此经常需要对该构件库进行扩展以增强其功能,如图

    在这里插入图片描述
    如何提高图形界面构件库性的可扩展性并降低其维护成本是Sunny公司开发人员必须面对的一个问题。

    设计

    在这里插入图片描述

    实现
    public interface Component {
    
        public void display();
    
    }
    
    public class TextBox implements Component{
    
        @Override
        public void display() {
            System.out.println("TextBox.display()");
        }
    
    }
    
    public class Window implements Component {
    
        public void display() {
    
            System.out.println("Window.display()");
    
        }
    
    }
    
    //构件装饰类:抽象装饰类
    public class ComponentDecorator implements Component {
    
        private Component component;  //维持对抽象构件类型对象的引用
    
        public ComponentDecorator(Component component)  //注入抽象构件类型的对象
        {
            this.component = component;
        }
    
        public void display() {
            component.display();
        }
    
    }
    
    //黑色边框装饰类:具体装饰类
    public class BlackBorderDecorator extends ComponentDecorator {
    
        public BlackBorderDecorator(Component component) {
    
            super(component);
    
        }
    
        public void display() {
    
            this.setBlackBorder();
            super.display();
    
        }
    
        public void setBlackBorder() {
    
            System.out.println("为构件增加黑色边框!");
    
        }
    
    }
    
    //滚动条装饰类:具体装饰类
    public class ScrollBarDecorator extends ComponentDecorator {
    
        public ScrollBarDecorator(Component component) {
            super(component);
        }
    
        public void display() {
    
            this.setScrollBar();
    
            super.display();
    
        }
    
        public void setScrollBar() {
    
            System.out.println("为构件增加滚动条!");
    
        }
    
    }
    
    测试
    public class Test {
    
        public static void main(String[] args) {
            Component component = new Window(); //定义具体构件
    
            Component componentSB = new ScrollBarDecorator(component); //定义装饰后的构件
    
            componentSB.display();
    
        }
    
    }
    

    2.3优缺点

    优点:
    • 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。
    • 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,得到功能更为强大的对象。
    • 增加新的功能很方便,无须修改已有系统,符合“开闭原则”。
    缺点:
    • 比继承更加灵活,也更容易出错

    在以下情况下可以考虑使用装饰模式:

    • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

    • 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式。

    不能采用继承的情况主要有两类:

    • 第一类是系统中存在大量独立的扩展,为支持每一种扩展或者扩展之间的组合将产生大量的子类,使得子类数目呈爆炸性增长;
    • 第二类是因为类已定义为不能被继承(如Java语言中的final类)。

    3.外观模式(Facade)

    3.1定义

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

    3.2例子

    需求

    文件加密模块设计
    某软件公司欲开发一个可应用于多个软件的文件加密模块,该模块可以对文件中的数据进行加密并将加密之后的数据存储在一个新文件中,具体的流程包括三个部分,分别是读取源文件、加密、保存加密之后的文件,其中,读取文件和保存文件使用流来实现,加密操作通过求模运算实现。这三个操作相对独立,为了实现代码的独立重用,让设计更符合单一职责原则,这三个操作的业务代码封装在三个不同的类中。

    如果在应用实例“文件加密模块”中需要更换一个加密类,不再使用原有的基于求模运算的加密类CipherMachine,而改为基于移位运算的新加密类NewCipherMachine

    设计

    在这里插入图片描述

    实现
    public class FileReader {
    
        public String Read(String fileNameSrc) {
            return "";
        }
    
    }
    
    public class FileWriter {
    
        public void Write(String encryptStr, String fileNameDes) {
    
        }
    
    }
    
    public class CipherMachine {
    
        // 数据加密
        public String Encrypt(String plainText) {
            return "";
        }
    
    }
    
    public class NewCipherMachine {
    
        // 数据加密
        public String Encrypt(String plainText) {
            return "";
        }
    
    }
    
    public abstract class AbstractEncryptFacade {
    
        public abstract void fileEncrypt(String fileNameSrc, String fileNameDes);
    }
    
    public class EncryptFacade extends AbstractEncryptFacade{
    
        //维持对其他对象的引用
        private FileReader reader;
        private CipherMachine cipher;
        private FileWriter writer;
    
        public EncryptFacade()
        {
            reader = new FileReader();
            cipher = new CipherMachine();
            writer = new FileWriter();
        }
    
        //调用其他对象的业务方法
        public void fileEncrypt(String fileNameSrc, String fileNameDes)
        {
            String plainStr = reader.Read(fileNameSrc);
            String encryptStr = cipher.Encrypt(plainStr);
            writer.Write(encryptStr, fileNameDes);
        }
    }
    
    public class NewEncryptFacade extends AbstractEncryptFacade {
    
        private FileReader reader;
    
        private NewCipherMachine cipher;
    
        private FileWriter writer;
    
        public NewEncryptFacade() {
            reader = new FileReader();
            cipher = new NewCipherMachine();
            writer = new FileWriter();
        }
    
        public void fileEncrypt(String fileNameSrc, String fileNameDes) {
            String plainStr = reader.Read(fileNameSrc);
            String encryptStr = cipher.Encrypt(plainStr);
            writer.Write(encryptStr, fileNameDes);
        }
    
    }
    
    测试
    public class Test {
    
        public static void main(String[] args) {
            AbstractEncryptFacade ef = new EncryptFacade();
            ef.fileEncrypt("src.txt", "des.txt");
    
            AbstractEncryptFacade ef2 = new NewEncryptFacade();
            ef2.fileEncrypt("src.txt", "des.txt");
    
        }
    
    }
    

    3.3优缺点

    优点:
    • 子系统与客户端间解耦
    • 一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
    缺点:
    • 如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则。
    适用场景:

    ​ (1) 当要为访问一系列复杂的子系统提供一个简单入口时可以使用外观模式。

    ​ (2) 客户端程序与多个子系统之间存在很大的依赖性。引入外观类可以将子系统与客户端解耦,从而提高子系统的独立性和可移植性。

    ​ (3) 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。

    4.代理模式(Proxy)

    4.1定义

    给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。

    常见的代理形式包括远程代理、保护代理、虚拟代理、缓冲代理、智能引用代理

    • 远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又称为大使(Ambassador)。
    • 虚拟代理(Virtual Proxy):如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
    • 保护代理(Protect Proxy):控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。
    • 缓冲代理(Cache Proxy):为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
    • 智能引用代理(Smart Reference Proxy):当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来等。

    4.2例子

    需求

    某软件公司承接了某信息咨询公司的收费商务信息查询系统的开发任务,该系统的基本需求如下:

    1. 在进行商务信息查询之前用户需要通过身份验证,只有合法用户才能够使用该查询系统;
    2. 在进行商务信息查询时系统需要记录查询日志,以便根据查询次数收取查询费用。

    该软件公司开发人员已完成了商务信息查询模块的开发任务,现希望能够以一种松耦合的方式向原有系统增加身份验证和日志记录功能,客户端代码可以无区别地对待原始的商务信息查询模块和增加新功能之后的商务信息查询模块,而且可能在将来还要在该信息查询模块中增加一些新的功能。

    设计

    在这里插入图片描述

    实现
    public interface Searcher {
    
        String doSearch(String userId, String keyword);
    }
    
    public class RealSearcher implements Searcher{
    
        @Override
        public String doSearch(String userId, String keyword) {
            return "001";
        }
    
    }
    
    
    //扩展功能 模拟实现登录验证
    public class AccessValidator {
    
        public boolean Validate(String userId) {
            return true;
        }
    
    }
    
    //扩展功能 模拟实现日志记录
    public class Logger {
    
        public void Log(String userId) {
            System.out.println("用户" + userId + "查询次数加1!");
        }
    
    }
    
    // 代理类
    public class ProxcySearcher implements Searcher {
    
        private RealSearcher searcher = new RealSearcher(); //维持一个对真实主题的引用
    
        private AccessValidator validator;
    
        private Logger logger;
    
        @Override
        public String doSearch(String userId, String keyword) {
            //如果身份验证成功,则执行查询
            if (this.validate(userId)) {
                System.out.println(userId+"用户验证通过");
                String result = searcher.doSearch(userId, keyword); //调用真实主题对象的查询方法
                this.log(userId); //记录查询日志
                return result; //返回查询结果
            } else {
                return null;
            }
        }
    
        //创建访问验证对象并调用其Validate()方法实现身份验证
        public boolean validate(String userId) {
            validator = new AccessValidator();
            return validator.Validate(userId);
        }
    
        //创建日志记录对象并调用其Log()方法实现日志记录
        public void log(String userId) {
            logger = new Logger();
            logger.Log(userId);
        }
    
    }
    
    
    测试
    public class Test {
    
        public static void main(String[] args) {
            Searcher searcher = new ProxcySearcher();
            String result = searcher.doSearch("杨过", "玉女心经");
        }
    
    }
    

    4.3优缺点

    优点:
    • 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
    • 客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则,系统具有较好的灵活性和可扩展性。
    缺点:
    • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢,例如保护代理。

    4.4动态代理

    对于静态代理,一个代理只能代理一个对象,如果有多个对象需要被代理,就需要很多代理类,造成代码的冗余。

    动态代理是相对于静态代理而提出的设计模式。在 Spring 中,有两种方式可以实现动态代理 —— JDK 动态代理和 CGLIB 动态代理。

    4.4.1JDK 动态代理

    JDK 代理的对象是动态生成的。JDK 代理的条件是被代理对象必须实现接口。

    // 1.定义接口
    public interface Action {
    	public void move();
    }
    // 2.定义被代理对象
    public class TargetAction implements Action{
        @Override
        public void move(){
            System.out.println("被代理对象TargetAction的move方法被调用");
        }
    }
    
    // 3.实现InvocationHandler接口,定义调用者
    public class ActionInvocationHandler implements InvocationHandler{
        private Action target;
        public Object bind(Action target){
            this.target = target;
            // 通过反射机制,创建一个代理对象实例并返回,用户进行方法调用时使用
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
        }
        @Override
        public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
            Object result = null;
            // 在动态代理类中,在被代理的方法前后可以加业务逻辑,不会破坏原方法
            // 调用前处理
           
            // 真正的业务
            result = method.invoke(target,args);
           
            // 调用后处理
            
            return result;
        }
    }
    
    // 4.测试
    public class Test{
        @Test
        public void testProxy(){
            //被代理对象
            TargetAction action = new TargetAction();
            // 动态代理类对象
            ActionInvocationHandler handler = new ActionInvocationHandler();
            // 代理对象
            Action proxy = handler.bind(action);
            proxy.move();
        }
    }
    

    动态代理类的生成过程可以归纳为以下一个步骤:

    1. 根据接口信息,新生成一个代理类的.java文件
    2. 根据.java,编译生成.class文件
    3. classloader读取class文件信息到jvm
    4. 新建对象,设置InvocationHandler参数。
    4.4.2CGLIB 动态代理

    在上面实现的 JDK 动态代理的方式中,不难发现 JDK 动态代理有一个缺点,即被代理类必须实现接口。这显然不能满足开发过程中的需要。有没有可能实现接口,直接就对 Java 类进行代理呢?这就需要 CGLIB 发挥作用了。

    // 1.定义被代理对象
    public class TargetAction {
        @Override
        public void move(){
            System.out.println("被代理对象TargetAction的move方法被调用");
        }
    }
    
    // 2.实现MethodInterceptor 接口,重写intercept方法
    public class ActionInvocationHandler implements MethodInterceptor{
    
        @Override
        public Object intercept(Object obj,Method method,Object[] objects,MethodProxy methodProxy)throws Throwable{
            Object result = null;
            // 在动态代理类中,在被代理的方法前后可以加业务逻辑,不会破坏原方法
            // 调用前处理
           
            // 真正的业务
            result = methodProxy.invokeSuper(obj,objects);
           
            // 调用后处理
            
            return result;
        }
    }
    // 3.定义代理类创建器
    public class CglibProxyCreator{
        public static <T> T create( Class<T> clazz, MethodInterceptor callbackinvoker){
            // 增强者
            Enhancer enhancer = new Enhancer();
            // 设置代理类
            enhancer.setSuperClass(clazz);
            // 设置Invoker
            enhancer.setCallback(callbackinvoker);
            return (T)enhancer.create();
        }
    }
    
    // 4.测试
    public class Test{
        @Test
        public void testProxy(){
            //被代理对象
            TargetAction action = new TargetAction();
            // 代理对象
            TargetAction proxy = CglibProxyCreator.create(TargetAction.class,new ActionInvocationHandler(action));
            proxy.move();
        }
    }
    

    五、行为型

    1.观察者模式(Observer)

    1.1 定义

    定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
    观察者模式的别名包括发布-订阅(P ublish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

    1.2例子

    需求

    微博消息推送

    设计

    在这里插入图片描述

    实现
    // 对象
    public abstract class Subject {
    
        //定义一个观察者集合用于存储所有观察者对象
        protected List<Observer> observers = new ArrayList();
    
        //注册方法,用于向观察者集合中增加一个观察者
        public void attach(Observer observer) {
            observers.add(observer);
        }
    
        //注销方法,用于在观察者集合中删除一个观察者
        public void detach(Observer observer) {
            observers.remove(observer);
        }
    
        //声明抽象通知方法
        public abstract void notifyMethod(String message);
    
    }
    
    public class ConcreteSubject extends Subject {
    
        //实现通知方法
        public void notifyMethod(String message) {
            //遍历观察者集合,调用每一个观察者的响应方法
            for (Object obs : observers) {
                ((Observer) obs).update(message);
            }
        }
    
    }
    
    //抽象观察者
    public interface Observer {
    
        //声明响应方法
        public void update(String message);
    
    }
    
    // 具体观察者
    public class ConcreteObserver implements Observer {
    
        // 微博用户名
        private String name;
    
        public ConcreteObserver(String name) {
            this.name = name;
        }
    
        //实现响应方法
        public void update(String message) {
            System.out.println("to " + name + ":" + message);
        }
    
    }
    
    测试
    public class Test {
    
        public static void main(String[] args) {
            Subject subject = new ConcreteSubject();
            // 创建观察者
            ConcreteObserver observer1 = new ConcreteObserver("dyn");
            ConcreteObserver observer2 = new ConcreteObserver("wxy");
            ConcreteObserver observer3 = new ConcreteObserver("jzy");
    
            // 将观察者放入观察者集合,订阅消息
            subject.attach(observer1);
            subject.attach(observer2);
            subject.attach(observer3);
    
            // 推送消息
            subject.notifyMethod("Jolin微博更新了");
        }
    
    }
    

    console

    to dyn:Jolin微博更新了
    to wxy:Jolin微博更新了
    to jzy:Jolin微博更新了
    

    1.3优缺点

    优点:
    • 观察者模式支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。
    • 观察者模式满足“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码
    缺点:
    • 观察者过多时,全部通知到比较耗时
    • 如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
    展开全文
  • jolin唱功越来越好了,呵呵 . 56。蔡依琳-说爱你。好听,推荐,校园里常放 . 57。陈亦迅-k歌之王。整张专辑《七》都不错啊 . 58。陈奕迅-十年。经典,听说惹得好多mm落泪,唉。。。。[心情连接]《十年》,感觉...
  • Outlook代理发送邮件方法: 方法一(直接在客户端设置): 1、 以Mary用户身份登录,打开客户端...3、 在弹出的“添加用户”对话框中,选择允许代表当前用户发送邮件的用户,如在Mary账户中添加用户Jolin,则表示允许...
  • let names = ["Jolin","Elva","Fish","Stefanie"] func backwards(s1: String,s2: String)->Bool{ return s1 > s2 } var reversed = sort(names,backwards) println(reversed) //[Stefanie, Jolin, Fish, Elva] ...
  • CSS的text-rendering属性

    千次阅读 2017-03-25 11:55:04
    var protocol = window.location.protocol; document.write(''); CSS 属性text-rendering的介绍和使用 - freshlover的专栏 - 博客频道 - CSDN.NET
  • body即函数主题可以调用任意的局部函数,局部函数也可以调用其他的局部函数,或者主函数的局部变量 (defun count-up (n) (labels ((count-up-recursively (cnt) (if (> cnt n) nil (cons cnt (count-up-...
  • 能装满你MP3的好歌

    2014-12-13 10:23:47
    103 范冰冰 - 花开自在(凌云壮志包青天的主题曲,娱乐圈里演而优则唱的事虽屡见不鲜,不过这首歌也确实值得推) 104 许慧欣-突然很想你(除了七月七月晴,俺最喜欢慧欣的这首歌了,相信听过就难忘了) 105 ...
  • yii sum

    千次阅读 2015-03-16 11:48:24
    transaction 多表&查询组件 视图嵌套 DetailViewDemo 验证规则 :自定义的规则 criteria查找:条件查找 Ajax 验证 多国语言 I18ndemo 加载样式 registerCss registerJavascript 主题替换 ThemeDemo UI组件,特效的...
  • 回到主题,我们动画中的前/后景翻转,实则是绕着x轴旋转90度。初步测试时,设好了旋转的属性和角度值,前/后景可以翻转了,但是却毫无立体感可言,不是从地面上“翻”起来,而像是从地面上“冒”出来似的,纵深方向...
  • music

    千次阅读 2011-10-24 15:07:33
    114 蔡依林 -天空(由元卫觉醒的韦斯利亲手谱曲的「天空」,以徐缓渐进的钢琴声推演成一曲澎湃的乐章,彷佛雨后的晴空出现彩虹,搭配jolin沉稳丰富的声音情绪,势必打动人心,成为经典传唱情歌…。) 115 璐璐-猫咪...
  • 103 范冰冰 - 花开自在(凌云壮志包青天的主题曲,娱乐圈里演而优则唱的事虽屡见不鲜,不过这首歌也确实值得推) 104 许慧欣-突然很想你(除了七月七月晴,俺最喜欢慧欣的这首歌了,相信听过就难忘了) 105 许哲佩...
  • 特别推荐:艾薇儿婚礼背景音乐--《Could This Be Love》超浪漫甜蜜的歌 ...麦当劳全球主题曲,不多说,大家自己去听,主打歌《 i’m lovin’it 》( 我就喜欢)是麦当劳2003年度最新广告歌的...
  • 收藏情歌

    2010-10-06 22:36:48
    51 《爱的天使》安志杰 JOLIN——电影的主题曲 52 《心动心痛》刘畊宏 许慧欣——曾经听了超难过的歌曲 53 《预言》范文芳 张宇——中国风 54 《只能抱着你》梁静茹 光良——想念过去~~ 55 《倾城之恋》孙悦 沙宝亮 ...
  • 敏捷中国大会2010四大主题:业务敏捷、管理实践、技术实践、组织变革,为技术团队搭建开放的交流平台。 现在报名,九折优惠 !Powered by ThoughtWorks 实际上,随着额外负载的增加,响应时间急剧攀升,数据库就...
  • KTV2人歌

    千次阅读 2009-04-17 15:20:00
    51 《爱的天使》安志杰 JOLIN——电影的主题曲 52 《心动心痛》刘畊宏 许慧欣——曾经听了超难过的歌曲 53 《预言》范文芳 张宇——中国风 54 《只能抱着你》梁静茹 光良——想念过去~~ 55 《倾城之恋》孙悦 ...
  • 多用户博客BLOG系统大全

    千次阅读 2009-09-10 20:17:00
    这样,一看就知道是JOLIN的BLOG。中文注册名:只能以UID做用户目录了。像 http://www.qrtt.com/u/44/index.html 中的44。谁也不知道这是张学友的BLOG,但它确实是!(^_^) 整合:跟动网论坛DVBBS,动易POWEREASY ...
  • 牛人在chinaren上的经典歌曲集

    千次阅读 2009-01-15 13:08:00
    1。陈慧琳-记事本。爱得痛了,痛的哭了,记载着我们过去的点点...麦当劳全球主题曲,不多说,大家自己去听,主打歌《 i’m lovin’it 》(我就喜欢)是麦当劳2003年度最新广告歌的华语版,此曲的英文版本由 justin timberl
  • 关于股市的大起大落有感!

    千次阅读 2008-03-13 18:26:00
    http://myweb.hinet.net/home7/kang36ta/jolin-ws.rar 5566 >传说 http://myweb.hinet.net/home7/kang36ta/5566.rar 王力宏I``m lovin`` it MV http://myweb.hinet.net/home5/cheerma/88001/hom.rar 王力宏>你不...
  • ms

    2007-05-15 15:50:00
    jolin唱功越来越好了,呵呵  56。蔡依琳-说爱你。好听,推荐,校园里常放  57。陈亦迅-k歌之王。整张专辑《七》都不错啊  58。陈奕迅-十年。经典,听说惹得好多mm落泪,唉。。。。[心情连接]《十年》,感觉就是一...
  • 必备歌曲--超经典

    千次阅读 2006-09-10 16:53:00
    jolin唱功越来越好了,呵呵 56。蔡依琳-说爱你。好听,推荐,校园里常放 57。陈亦迅-k歌之王。整张专辑《七》都不错啊 58。陈奕迅-十年。经典,听说惹得好多mm落泪,唉。。。。[心情连接]《十年》,感觉就是一个蛮...
  • 好歌曲

    2006-08-14 16:50:00
    jolin唱功越来越好了,呵呵 .  56。蔡依琳-说爱你。好听,推荐,校园里常放 .  57。陈亦迅-k歌之王。整张专辑《七》都不错啊 .  58。陈奕迅-十年。经典,听说惹得好多mm落泪,唉。。。。[心情连接]《十年》,...
  • mp3中不可缺少的音乐

    千次阅读 2006-07-28 12:40:00
    麦当劳全球主题曲,不多说,大家自己去听主打歌《i’m lovin’it》(我就喜欢)是麦当劳2003年度最新广告歌的华语版,此曲的英文版本由justin timberlake演唱。生活化风味浓烈的歌词配以流畅的休闲节奏,王力宏用hip-...
  • http://txt.mop.com/static/788/231/5231788.html

    千次阅读 2005-04-11 16:34:00
    麦当劳全球主题曲,不多说,大家自己去听[连接]主打歌《 i’m lovin’it 》(我就喜欢)是麦当劳2003年度最新广告歌的华语版,此曲的英文版本由 justin timberlake演唱。生活化风味浓烈的歌词配以流畅的休闲节奏,...
  • 大家好,我是杂烩君。嵌入式大杂烩周记主要是一些实用项目学习分享,每周一篇,每篇一个主题。内容主要来源于我们之前收集的资料:https://gitee.com/zhengnianli/Emb...

空空如也

空空如也

1 2
收藏数 30
精华内容 12
热门标签
关键字:

joplin 主题

友情链接: readdata_paths.rar