第一章 系统体系结构

1.基本概述
        系统设计包含:体系结构设计和程序的详细设计;体系结构简单来讲解决的是软件或系统部署的问题;程序的详细设计:应用程序功能的问题。
2.物理体系结构
        物理体系结构解决客户机和服务器及中间件问题-部署
2.1.对等体系结构
        概述:具有数据库的计算机节点,都可能既是客户机又是服务器,通过通信网络将这些结点连接起来形成对等体系结构;中心组织原则是:任何结点都可以自由地直接与任何其他结点通信,而无需中间服务器;优点:易于快速修复网络故障,易于扩展和适应;缺点:系统吞吐量达到最大时,容易发生死锁。结构图:

 2.2.分层体系结构
        概述:大多数企业信息系统使用多层体系结构,典型的是三层,应用于开发大型数据库为中心的企业系统页面表示层、业务逻辑层、数据层,在三层体系结构中,业务逻辑位于GUI客户机和数据库服务器之间。在实际应用中,可以不限于3层,有可包含web处理、网络通信、打印等其它服务。MVC层:

 2.3.数据库为中心的体系结构
        概述:程序(客户端)与数据库(服务器)交互,获得信息展示和用户操作信息,也可对数据库编程。结构图

 3.体系结构模式设计
        设计模式原则:总原则:开闭原则;对扩展开放,对修改关闭。在程序需要进行扩展时,不能去修改原有的代码,而是扩展原有的代码,实现可插拔的效果。一句话:为了使程序易于扩展、维护和升级,需要使用接口和抽象类。
3.1.单一职责原则
        每个类应该实现单一的职责,如果不行,应该把类进行拆分。
3.2.里氏替换原则
        任何基类可以出现的地方,子类一定可以出现在里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个接口和外界交互,子类不应该随便破坏它。
3.3.依赖倒转原则
        是开闭原则的基础;面向接口编程,依赖于抽象而不依赖于具体;写代码时用到具体的类时,不应该和具体类的交互,而是与具体类的上层接口交互。
3.4.接口隔离原则
        每个接口中不应该存在子类用不到却必须实现的方法,否则的话就要将接口拆分成多个接口。
3.5.迪米特法则
        也叫最少知道原则。一个类对自己依赖的类知道的越少越好。强调的是封装的问题。
3.6合成复用原则
        原则是尽量首先把功能使用聚合方式,而不是使用集成。
4.常见的体系结构设计模式
4.1.外观模式

4.1.1.外观模式含义
        一种通过为多个子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部的应用程序不用关心内部子系统的具体的细节,这样就降低了应用程序的复杂度,提高了程序的可维护性。外观模式是为了解决类与类之间的依赖关系,降低了类类之间的耦合度。
4.1.2.外观模式的结构:以电脑启动解释外观模式

4.1.3.外观模式的优点和缺点
        优点是:降低了子系统和客户端之间的耦合度,子系统的变化不会影响到调用它的客户类;对客户屏蔽了子系统组件,减少客户处理的对象数目,并使得子系统使用起来更加容易。
        缺点是;增加新的子系统可能需要修改外观类或客户端源代码,从这一点来讲违背了“开闭原则”。
4.1.4.外观模式主要角色
        外观角色:为多个子系统对外提供一个共同的接口
        子系统角色:实现系统的部分功能,客户角色可以通过外观角色访问
        客户角色:通过一个外观角色访问各个子系统的功能。
4.1.5.代码实现如下:子系统角色cpu、memory和disk

//CPU类-子系统角色
public class Cpu {
    public void startup(){
        System.out.println("cpu启动");
    }
    public void shutdown(){
        System.out.println("cpu关闭");
    }
}

//内存类-子系统角色
public class Memory {
    public void startup(){
        System.out.println("Memory-启动");
    }
    public void shutdown(){
        System.out.println("Memory-关闭");
    }
}

//桌面类-子系统角色
public class Disk {
    public void startup(){
        System.out.println("Disk-启动");
    }
    public void shutdown(){
        System.out.println("Disk-关闭");
    }
}
//外观角色-电脑
public class Computer {
    private Cpu cpu =new Cpu();
    private Disk disk=new Disk();
    private Memory mem=new Memory();
    public void startup(){
        System.out.println("电脑开始启动");
        cpu.startup();
        disk.startup();
        mem.startup();
        System.out.println("电脑启动完毕");
    }
    public void shutdown(){
        System.out.println("电脑开始关机");
        cpu.shutdown();
        disk.shutdown();
        mem.shutdown();
        System.out.println("电脑关机完毕");
    }
}


//客户端角色-用户
public class User {
    public static void main(String[] args) {
        Computer cm =new Computer();
        cm.startup(); //开机
        System.out.println("----------------");
        cm.shutdown();//关机
    }
}

4.1.6.外观角色练习

//子系统1
public class System01 {
    public void method1(){
        System.out.println("子系统01的-method1方法-被调用");
    }
}

//子系统2
public class System02 {
    public void method2(){
        System.out.println("子系统02的-method2方法-被调用");
    }
}

//子系统3
public class System03 {
    public void method3(){
        System.out.println("子系统03的-method3方法-被调用");
    }
}

//外观者角色
public class Facade {
    private System01 sys1=new System01();
    private System02 sys2=new System02();
    private System03 sys3=new System03();
    //调用子系统方法功能
    public void method(){
        sys1.method1();
        sys2.method2();
        sys3.method3();
    }
}

//客户角色需要面对 外观角色
public class TestFacade {
    public static void main(String[] args) {
        new Facade().method(); //调用方法
    }
}

 4.2.简单工厂模式
        简单工厂模式主要解决生成相应的对象。简单工厂一般分为:普通简单工厂、多方法简单工厂、静态方法简单工厂。

4.2.1.普通简单工厂实现:工厂接口和发送器

//发送接口
public interface Sender {
    void send(); //发送方法
}

//邮件发送器
public class MailSender implements Sender {
    @Override
    public void send() {
        System.out.println("这是-邮件-发送器");
    }
}

//短信发送器
public class MsgSender implements Sender {
    @Override
    public void send() {
        System.out.println("这是-短信-发送器");
    }
}

工厂类生成发送器

//发送器工厂
public class SenderFactory {
    //生产发送器对象
    public Sender produce(String type){
        if("mail".equals(type)){
            return new MailSender();
        }else if("msg".equals(type)){
            return new MsgSender();
        }else{
            System.out.println("请输入正确的类型");
            return null;
        }
    }
}


//普通简单工厂测试
public class SimpleFactoryTest {
    public static void main(String[] args) {
        SenderFactory sf=new SenderFactory(); //发送器工厂对象
        Sender sender=sf.produce("mail"); //生产发送器
        sender.send();
        System.out.println("--------------");
        Sender sender1=sf.produce("msg");
        sender1.send();
    }
}

4.2.2.多方法简单工厂
        是对普通简单工厂方法模式的改进,在普通简单工厂方法模式中,如果传递的字符串出错,就不能正确的创建相应的对象。多方法简单工厂模式是提供多个工厂方法,分别创建对象。

//发送器工厂
public class SenderFactory {
    //邮件发送器
    public Sender produceMailSender(){
        return new MailSender();
    }
    //短信发送器
    public Sender produceMsgSender(){
        return new MsgSender();
    }
}

// 测试多方法简单工厂
//多方法简单工厂测试
public class ManyMethodFactoryTest {
    public static void main(String[] args) {
        SenderFactory sf=new SenderFactory(); //发送器工厂对象
        sf.produceMailSender().send(); //邮件发送器
        sf.produceMsgSender().send(); //短信发送器
    }
}

4.2.3.静态方法简单工厂
        将多方法简单工厂中方法设置为静态的,不需要创建实例(不需要new),直接调用即可。
        改动多方法普通工厂类

//发送器工厂
public class SenderFactory {
    //邮件发送器
    public static Sender produceMailSender(){
        return new MailSender();
    }
    //短信发送器
    public static Sender produceMsgSender(){
        return new MsgSender();
    }
}

//静态方法简单工厂测试
public class StaticMethodFactoryTest {
    public static void main(String[] args) {
        SenderFactory.produceMailSender().send(); //邮件发送器 发送消息
        System.out.println("--------------");
        SenderFactory.produceMsgSender().send(); //短信发送器 发送消息
    }
}

4.2.4.工厂方法模式,简单工厂存在的问题
        
简单工厂模式中,类的创建依赖玉工厂类,如果想要扩展程序,必须对工厂类进行修改,违背了开闭原则。从设计的角度考虑,简单工厂模式存在一定的问题,用工厂方法模式解决。
4.2.5.工厂方法模式结构

4.2.6.工厂方法模式实现:发送接口和发送接口的实现类

//发送接口
public interface Sender {
    void send(); //发送方法
}

//邮件发送器
public class MailSender implements Sender {
    @Override
    public void send() {
        System.out.println("这是-邮件-发送器");
    }
}

//短信发送器
public class MsgSender implements Sender {
    @Override
    public void send() {
        System.out.println("这是-短信-发送器");
    }
}

        生成接口和 工厂类

//生产接口
public interface Provider {
    Sender produce(); //生产发送器
}

//邮件发送器工厂
public class MailFactory implements Provider {
    @Override
    public Sender produce() {
        return new MailSender();
    }
}

//短信发送器工厂
public class MsgFactory implements Provider {
    @Override
    public Sender produce() {
        return new MsgSender();
    }
}


//工厂方法模式测试
public class FactoryMethodTest {
    public static void main(String[] args) {
        Provider pv=new MailFactory();
        Sender mailSender=pv.produce(); //生产邮件发送器
        mailSender.send();
        System.out.println("------------");
        Provider pv1=new MsgFactory();
        Sender msgSender=pv1.produce(); //生产短信发送器
        msgSender.send();
    }
}

        如果现在需要增加一个发消息功能,我们只需要做一个实现类,实现发送接口,同时声明一个工厂类,实现生产接口就可以了,不需要改动现在代码,扩展性好。
4.2.7.抽象工厂模式
        工厂方法模式中考虑的是一类产品的生产(一个产品等级);抽空工厂模式考虑多等级产品的生产;将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族。

         概念:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,而且访问类不需要指定所要产品的具体类就能得到同族的不同等级的产品的模式结构;抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
        抽象工厂模式条件:系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品;系统一次只可能消费其中某一族产品,即同族的产品一起使用。
        抽象工厂模式优点:抽象工厂模式除了具有工厂方法模式的优点外还有以下优点:可以在类的内部对产品族中相关联的多等级产品共同管理,不必引入新的类来进行管理;增加新的产品族时,不需要修改原代码,满足开闭原则。
        抽象工厂模式缺点:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
        抽象工厂主要角色:抽象工厂:提供创建产品的接口,包含多个创建产品的方法创建多个不同等级的产品;具体工厂:实现抽象工厂中的多个抽象方法,完成具体产品的创建;抽象产品:定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品;具体产品:实现抽象产品接口,是由具体的工厂来创建。
        抽象工厂实现:以生成电器,不同产品、不同生产商为例。

// 产品抽象接口
// 冰箱描述接口
public interface BxInterface {
    public void bxInfo(); //冰箱描述
}

//空调描述接口
public interface KtInterface {
    public void ktInfo(); //空调描述
}

// 电器工厂接口
//电器工厂接口
public interface DqFactory {
    public KtInterface createKt(); //创建空调
    public BxInterface createBx(); //创建冰箱
}


// 具体工厂类1
//美的工厂类
public class MdFactory implements DqFactory {
    @Override
    public KtInterface createKt() {
        System.out.println("生产美的-空调");
        return new MdKt();
    }
    @Override
    public BxInterface createBx() {
        System.out.println("生产美的-冰箱");
        return new MdBx();
    }
}
// 具体产品类
//美的冰箱具体类
public class MdBx implements BxInterface {
    @Override
    public void bxInfo() {
        System.out.println("美的冰箱very good!");
    }
}
//美的 空调具体类
public class MdKt implements KtInterface {
    @Override
    public void ktInfo() {
        System.out.println("美的空调very good!");
    }
}

// 具体工厂类2-海尔
//海尔工厂类
public class HrFactory implements DqFactory {
    @Override
    public KtInterface createKt() {
        System.out.println("生产海尔-空调");
        return new HrKt();
    }
    @Override
    public BxInterface createBx() {
        System.out.println("生产海尔-冰箱");
        return new HrBx();
    }
}

// 具体海尔产品类
//海尔冰箱 具体类
public class HrBx implements BxInterface {
    @Override
    public void bxInfo() {
        System.out.println("海尔冰箱very good!");
    }
}
//海尔空调具体类
public class HrKt implements KtInterface {
    @Override
    public void ktInfo() {
        System.out.println("海尔空调very good!");
    }
}

// 抽象工厂模式测试
public class TestAbstractFactory {
    public static void main(String[] args) {
        //海尔生产冰箱和空调
        DqFactory hrf=new HrFactory(); //创建海尔工厂
        BxInterface hbx=hrf.createBx(); //生产冰箱
        hbx.bxInfo(); //冰箱的描述
        KtInterface hkt=hrf.createKt();//生产空调
        hkt.ktInfo(); //空调的描述
        System.out.println("---------------------");
        //美的生产冰箱和空调
        DqFactory mrf=new MdFactory();
        BxInterface mbx=mrf.createBx();
        mbx.bxInfo();
        KtInterface mkt=mrf.createKt();
        mkt.ktInfo();
    }
}

        抽象工厂应用场景:当需要创建的对象是一系列相关联或相互依赖的产品族时。例如电器工厂中的电视机、洗衣机、空调等;系统中有多个产品族,但每次只使用其中的某一族产品。例如有些人喜欢穿某一个品牌的衣服和鞋等其它产品;系统中提供了产品的类库且所有产品的接口相同,客户端不依赖产品实例创建细节。
4.3.责任链模式
        概念:为了避免请求发起者和多个请求处理者耦合在一起,将所有请求的处理者通过前一个对象记住下一个对象的引用而连成一条链条;当有请求时,可将请求沿着这条链进行传递,知道有相应的对象处理为止。也称为职责链模式。
4.3.1.责任链模式发奖金结构图

4.3.2.责任链模式主要角色
        抽象处理者角色
:定义了一个处理请求的抽象类,包含抽象处理方法和一个后继处理者连接
        具体的处理者角色:实现抽象处理者的处理方法,判断是否可以处理本次请求,如果可以则处理,否则将请求转发给下一位具体处理者
        客户端角色:
创建处理链,并向链条头的具体处理者提交请求。客户端并不关心处理细节和请求传递过程。
4.3.3.责任链结构

 4.3.4.客户端组装责任链结构

 4.3.5.责任链模式实现

//抽象处理者角色
public abstract class Handler {
    private Handler next; //下一个具体处理者引用
    //处理请求的方法
    public abstract void handleRequest(String req);
    public Handler getNext() {
        return next;
    }
    public void setNext(Handler next) {
        this.next = next;
    }
}

//具体处理者1
public class OpHandler1 extends Handler {
    @Override
    public void handleRequest(String req) {
        if(req.equals("one")){
            System.out.println("具体处理者1 负责该请求的处理");
        }else{
            if(getNext()!=null){
                getNext().handleRequest(req); //下一个具体的处理者
            }else{
                System.out.println("没有人处理该请求!");
            }
        }
    }
}


//具体处理者2
public class OpHandler2 extends Handler {
    @Override
    public void handleRequest(String req) {
        if(req.equals("two")){
            System.out.println("具体处理者2 负责该请求的处理");
        }else{
            if(getNext()!=null){
                getNext().handleRequest(req); //下一个具体的处理者
            }else{
                System.out.println("没有人处理该请求!");
            }
        }
    }
}
//客户端角色-测试责任链模式
public class ClientUser {
    public static void main(String[] args) {
        //1-组装责任链
        Handler h1=new OpHandler1();
        Handler h2=new OpHandler2();
        h1.setNext(h2);
        //2-发送请求
        h1.handleRequest("two");
    }
}

4.3.6.责任链练习需求
        需求描述:用责任链模式设计一个请假条审批模块,规定学生请假<=2天,班主任可以批准;<=7天,系主任可以批准;<=10天,院长可以批准;其它情况不予批准。
需求结构图

//抽象处理者-领导类
public abstract class Leader {
    private Leader next;//下一个具体的处理者引用
    public abstract void handleRequest(int days); //批假
    public Leader getNext() {
        return next;
    }
    public void setNext(Leader next) {
        this.next = next;
    }
}

//具体的处理者-班主任
public class Bzr extends Leader {
    @Override
    public void handleRequest(int days) {
        if(days<=2){
            System.out.println("班主任批准您请假"+days+"天!");
        }else{
            if(getNext()!=null){
                getNext().handleRequest(days);
            }else{
                System.out.println("请假天数过多,无人批准!");
            }
        }
    }
}
//具体的处理者-系主任
public class Xzr extends Leader {
    @Override
    public void handleRequest(int days) {
        if(days<=7){
            System.out.println("系主任批准您请假"+days+"天!");
        }else{
            if(getNext()!=null){
                getNext().handleRequest(days);
            }else{
                System.out.println("请假天数过多,无人批准!");
            }
        }
    }
}
//具体的处理者-院长
public class Yz extends Leader {
    @Override
    public void handleRequest(int days) {
        if(days<=10){
            System.out.println("院长批准您请假"+days+"天!");
        }else{
            if(getNext()!=null){
                getNext().handleRequest(days);
            }else{
                System.out.println("请假天数过多,无人批准!");
            }
        }
    }
}
//客户端角色-测试责任链模式
public class ClientStu {
    public static void main(String[] args) {
        //1-组装责任链
        Leader l1=new Bzr();
        Leader l2=new Xzr();
        Leader l3=new Yz();
        l1.setNext(l2);
        l2.setNext(l3);
        //2-发送请求
        l1.handleRequest(8);
    }
}

4.3.7.责任链模式的优缺点
        优点:
降低了对象之间的耦合度。客户角色不需要知道是哪一个具体处理者处理其请求,发送者和接收者也不需要拥有对方的明确信息;增强了系统的可扩展性。可以根据需要增加具体的处理者,满足开闭原则;增强了给具体对象指派职责的灵活性。当工作流程发生变化,可以动态的增删处理者,也可调整或者改变处理者的次序。
        简化了对象之间的连接。每个具体处理者只需保持一个指向下一个处理者的引用,不需要保持其他所有处理者的引用;责任分担。每个具体处理者只需要处理自己该处理的工作,不该处理的传递给下一个处理者即可,明确各类的责任范围。
        缺点:不能保证每个请求都得到正确处理;对比较长的职责链,请求处理涉及到处理对象比较多,系统性能将收到一定的影响;要靠客户端保证处理的合理性,有可能会造成相应的问题,例如:循环调用。
        责任链模式应用场景:有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定;有需要动态指定一组对象处理请求,或者添加新的处理者;在不明确指定请求处理者的情况下,向多个处理者中的一个处理者提交请求。
4.4.观察者模式
        概念:
多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖与此对象都得到通知并被自动更新。这种模式也称为发布-订阅模式,有时也称为模型-视频模式。
4.4.1.角色
        抽象主题角色:
也称为抽象目标类,它提供了一个用于观察者对象的增删方法以及通知观察者的抽象方法。
        具体主题角色:也称为具体目标类,它实现抽象主题目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
        抽象观察者角色:它是一个抽象类或接口,包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
        具体观察者角色:实现抽象观察者中定义的抽象方法,以便在得到目标更改通知时更新自身的状态。
4.4.2.观察者模式结构图

4.4.3.观察者模式实现

//抽象观察者
public interface ObServer {
    void response(); //作出反应
}

//具体的观察者1
public class Observer1 implements ObServer {
    @Override
    public void response() {
        System.out.println("具体的观察者1作出反应!");
    }
}

//具体的观察者2
public class Observer2 implements ObServer {
    @Override
    public void response() {
        System.out.println("具体的观察者2作出反应!");
    }
}
//抽象主题角色-抽象目标角色
public abstract class Subject {
    protected List<ObServer> obs=new ArrayList<ObServer>(); //抽象观察者集合
    //增加观察者方法
    public void add(ObServer obsv){
        obs.add(obsv);
    }
    //删去观察者方法
    public void remove(ObServer obsv){
        obs.remove(obsv);
    }
    //通知观察者方法
    public abstract void notifyObs();//通知观察者方法
}

//具体目标类
public class OpSubject extends Subject {
    @Override
    public void notifyObs() {
        System.out.println("老师下午课程有变化");
        for (ObServer obr : obs) {
            obr.response(); //通知
        }
    }
}


//测试观察者
public class TestGuanChaZhe {
    public static void main(String[] args) {
        Subject sub=new OpSubject(); //具体的目标者
        ObServer obs1=new Observer1();//具体的观察者1
        ObServer obs2=new Observer2(); //具体的观察者2
        sub.add(obs1);
        sub.add(obs2);
        sub.notifyObs(); //通知方法
    }
}

 4.4.4.观察者模式的有缺点
        优点:
降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系;目标与观察者之间建立了一套触发机制。
        缺点:目标和观察者之间的依赖关系并没有完全解除,有可能出现循环引用;当观察者很多时,通知的发布|动作会花很多时间,影响程序的效率
4.4.5.观察者模式应用场景
       
对象间存在一对多关系,一个对象状态的改变会影响到其它对象
4.4.5.观察者模式练习需求
        整体需求:
利用观察者模式设计一个学校铃声的事件处理程序。
        案例分析:学校的"铃"是事件源和目标,老师和学生是具体的观察者,"铃声"是事件类;学生和老师都会注意到学校的铃,这叫事件绑定;当上课或下课时间到会触发铃发声,这个时候会生成"铃声"事件;学生和老师听到铃声会开始上课或者下课-这叫事件处理。
        案例思路:有一个铃声事件类(记录铃声类型-上课和下课铃声)
2-定义一个学校的铃(观察者目标类)-包含了监听器容器,可以绑定监听者类(老师或学生),且包含产生铃声事件和通知所有监听者(老师或学生)方法;定义一个抽象观察者(抽象监听者类)-包含铃声事件处理方法;定义具体的观察者类(老师和学生)-事件监听者-听到铃声会上课或下课。

//铃声事件类-用于分钟事件源及铃声相关的参数
public class BellEvent extends EventObject {
    private static final long serialVersionUID = 1L;
    private boolean sound; //铃声类型-true为上课,false为下课
    public BellEvent(Object source,boolean sound) {
        super(source);
        this.sound=sound;
    }
    public boolean isSound() {
        return sound;
    }
    public void setSound(boolean sound) {
        this.sound = sound;
    }
}


//抽象观察者类-铃声事件 监听器
public interface BellEventListener extends EventListener {
    //事件处理方法-听到铃声
    public void listenBell(BellEvent be);
}


//具体观察者1-老师事件监听器
public class TeacherEventListener implements BellEventListener {
    @Override
    public void listenBell(BellEvent be) {
        if(be.isSound()){
            System.out.println("老师上课");
        }else{
            System.out.println("老师下课");
        }
    }
}

//具体观察者2-学生事件监听器
public class StuEventListener implements BellEventListener {
    @Override
    public void listenBell(BellEvent be) {
        if(be.isSound()){
            System.out.println("学生上课");
        }else{
            System.out.println("学生下课");
        }
    }
}
//事件源-目标类-铃
public class Bell {
    //抽象观察者集合-监听器容器
    private List<BellEventListener> listener=new ArrayList<BellEventListener>();
    //添加抽象观察者-将监听器加入到监听器容器中
    public void addListener(BellEventListener bel){
        listener.add(bel);
    }
    //事件触发器,当铃声sound的值发生变化时 触发
    public void ring(boolean sound){
        String type=sound?"上课铃":"下课铃";
        System.out.println(type+"响了!");
        notifys(new BellEvent(this,sound)); //通知
    }
    //通知
    private void notifys(BellEvent bell) {
        BellEventListener bl=null;
        Iterator<BellEventListener> it = listener.iterator();
        while(it.hasNext()){
            bl=it.next();
            bl.listenBell(bell);//听到铃声
        }
    }
}

//测试观察者模式
public class TestGcz {
    public static void main(String[] args) {
        Bell bl=new Bell(); //事件源-目标类-铃
        bl.addListener(new TeacherEventListener()); //注册监听器(老师)
        bl.addListener(new StuEventListener()); //注册监听器(学生)
        bl.ring(true); //打上课铃
        System.out.println("-----------------");
        bl.ring(false);//打下课铃
    }
}

4.5.中介者模式
        引入:在现实生活中,经常出现多个对象存在复杂的交互关系,这种交互关系通常是网状结构,例如租房子,可以找中介,找工作可以找人才服务中心;QQ聊天程序也存在中介者-QQ服务器;所有现实中类似的案例都可以采用中介者模式实现,降低了对象之间的耦合性,提高系统的灵活性。
        概念:定义一个中介对象封装一系列对象之间的交互关系,使原有对象间耦合松散且可以独立改变原有对象间的交互,中介者模式又称为调停模式。
4.5.1.角色
        抽象中介者角色:
是具体中介者的接口,提供学生对象注册和转发学生对象信息的方法
        具体中介者角色:实现中介者接口,定义一个集合来管理学生对象,协调学生之间的交互关系。依赖于学生对象
        抽象学生类:定义学生类的接口,保存中介者对象,提供学生之间交互的抽象方法。
        具体学生类:是抽象学生类的实现者,当需要和其它同学交流时,由中介者对象负责后续交互或传话。
4.5.2.结构图

 4.5.3.实现

//抽象中介者
public abstract class Broker {
    //抽象学生类注册
    public abstract void reg(AbstractStu as);
    //转发学生对象信息
    public abstract void forwardMsg(AbstractStu as);
}

//抽象学生类
public abstract class AbstractStu {
    protected Broker bk; //抽象中介者
    //接收消息
    public abstract void reMsg(); //接收消息
    //发送消息
    public abstract void seMsg(); //发送消息
    public Broker getBk() {
        return bk;
    }
    public void setBk(Broker bk) {
        this.bk = bk;
    }
}


//具体学生类1
public class Stu1 extends AbstractStu {
    @Override
    public void reMsg() {
        System.out.println("具体学生类1-收到请求");
    }
    @Override
    public void seMsg() {
        System.out.println("具体学生类1-发送请求");
        bk.forwardMsg(this); //请中介者转发
    }
}

//具体学生类2
public class Stu2 extends AbstractStu {
    @Override
    public void reMsg() {
        System.out.println("具体学生类2-收到请求");
    }
    @Override
    public void seMsg() {
        System.out.println("具体学生类2-发送请求");
        bk.forwardMsg(this); //请中介者转发
    }
}
//具体中介者
public class JtBroker extends Broker {
    private List<AbstractStu> sStus=new ArrayList<AbstractStu>();
    @Override
    public void reg(AbstractStu as) { //注册
        if(!sStus.contains(as)){
            sStus.add(as);
            as.setBk(this); //设置中介者
        }
    }
    @Override
    public void forwardMsg(AbstractStu astu) { //转发
        for (AbstractStu as : sStus) {
            if(!as.equals(astu)){
                as.reMsg();
            }
        }
    }
}

//测试中介者模式
public class TestBroker {
    public static void main(String[] args) {
    Broker bk =new JtBroker(); //具体中介者
    AbstractStu as1=new Stu1(); //具体学生类1
    AbstractStu as2=new Stu2(); //具体学生类2
    bk.reg(as1);
    bk.reg(as2);
    as1.seMsg();//发送消息
    System.out.println("-----------");
    as2.seMsg();//发送消息
    }
}

4.5.3.应用场景
        当对象间存在复杂的网状关系造成依赖关系混乱并且不容易复用;当想要创建一个运行于多个类之间的对象时。
4.5.4.简化中介模式
        在实际开发中,一般都会简化中介模式:不定义中介者接口,把具体的中介者对象实现为单例;抽象学生类中不持有中介者,而是在需要的时候直接获取中介者对象即可。
4.5.5.简化中介结构

 4.5.6.简化中介实现

//抽象学生类-接口
public interface AbstractStu {
    //接收消息
    public abstract void receiveMsg(); //接收消息
    //发送消息
    public abstract void sendMsg(); //发送消息
}

//单例-中介者
public class JtBroker{
    private static JtBroker jbk=new JtBroker();
    private List<AbstractStu> stus=new ArrayList<AbstractStu>();
    //私有化构造方法
    private JtBroker(){}
    //获得中介者
    public static JtBroker getJtBroker(){
        return jbk;
    }
    //注册
    public void regStu(AbstractStu as){
        if(!stus.contains(as)){
            stus.add(as);
        }
    }
    //转发消息
    public void forwardMsg(AbstractStu as){
        for (AbstractStu abs : stus) {
            if(!abs.equals(as)){
                abs.receiveMsg();
            }
        }
    }
}
//具体学生类1
public class Stu1 implements AbstractStu {
    public Stu1(){
        JtBroker.getJtBroker().regStu(this);
    }
    @Override
    public void receiveMsg() {
        System.out.println("具体学生1-收到请求");
    }
    @Override
    public void sendMsg() {
        System.out.println("具体学生1-发送请求");
        JtBroker.getJtBroker().forwardMsg(this); //中介转发
    }
}


//具体学生类2
public class Stu2 implements AbstractStu {
    public Stu2(){
        JtBroker.getJtBroker().regStu(this);
    }
    @Override
    public void receiveMsg() {
        System.out.println("具体学生2-收到请求");
    }
    @Override
    public void sendMsg() {
        System.out.println("具体学生2-发送请求");
        JtBroker.getJtBroker().forwardMsg(this); //中介转发
    }
}

//测试简化中介者模式
public class TestJhBroker {
    public static void main(String[] args) {
        AbstractStu as1=new Stu1(); //具体学生类1
        AbstractStu as2=new Stu2(); //具体学生类2
        as1.sendMsg();//发送消息
        System.out.println("-----------");
        as2.sendMsg();//发送消息
    }
}

4.6.装饰模式
4.6.1.基本概念
        
装饰模式是动态的给一个对象添加一些额外的功能,就增加功能来说,装饰
模式比生成子类更为灵活。装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。提供比继承更多的灵活性。装饰模式是创建一个包装对象,也就是使用装饰来包裹真实的对象。
4.6.2.装饰模式的实现
        
装饰对象和真实对象有相同的接口/抽象类。这样客户端对象就能以和真实对象相同的方式和装饰对象交互;装饰对象包含一个真实对象的引用(reference);装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象;装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
4.6.3.适用性
        
需要扩展一个类的功能,或给一个类添加附加职责;需要动态的给一个对象添加功能,这些功能可以再动态的撤销;需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩
展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
4.6.4.代码实现

//变形金刚在变形前是一辆汽车,它可以在陆地上移动。当它变成机器人之后除了能够在陆地上移动之外,还可以说话;
//如果需要,它还可以变成飞机,除了在陆地上移动还可以在天空中飞翔。
//声明一个move方法,无论变形金刚如何改变该方法始终都有,是具体构件和抽象装饰类共有的方法。
interface Transform {
    public void move();
}


//ConcreteComponent(具体构件):Car.java 提供了move方法的实现,运用构造函数初始化输出当前状态,它是一个可以被装饰的类。在这里Car
//被声明为final类型,说明不能通过继承来拓展其功能,需运用类之间的关联关系来拓展。即装饰器装饰
final class Car implements Transform {
    // 初始化
    public Car() {
        System.out.println("变形金刚->车");
    }
    @Override
    public void move() {
        System.out.println("在陆地上移动");
    }
}

//Decorator(抽象装饰类):Changer.java 定义一个抽象构件类型的
//transform,通过构造函数或者setter方法来给该对象赋值,同时也通过调用transform对象
//来实现move方法,这样可以保证原方法不被丢失,而且可以在它的子类中增加新的方法,拓展原有功能。
class Changer implements Transform {
    private Transform transform;
    public Changer(Transform transform) {
        this.transform = transform;
    }
    @Override
    public void move() {
        transform.move();
    }
}
//ConcreteDecorator(具体装饰类):这里采用的是半透明
class Robot extends Changer {
    public Robot(Transform transform) {
        super(transform);
        System.out.println("->机器人");
    }
    @Override
    public void move() {
        super.move();
        say();
    }
    private void say() {
        System.out.println("说话");
    }
}


class Airplane extends Changer {
    public Airplane(Transform transform) {
        super(transform);
        System.out.println("->飞机");
    }
    @Override
    public void move() {
        super.move();
        fly();
    }
    private void fly() {
        System.out.println("飞翔");
    }
}


public class DecoratorDemo {
    public static void main(String[] args) {
        Transform machine = new Car();
        machine.move();
        Robot robot = new Robot(machine);
        robot.move();
        Airplane airplane1 = new Airplane(machine);
        airplane1.move();
        Airplane airplane2 = new Airplane(robot);
        airplane2.move();
    }
}

4.6.5.装饰器模式的应用场景
        
需要扩展一个类的功能。动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)
4.6.6.缺点
        
这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性;装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂;装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变 Component 接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
4.6.7.装饰模式和代理模式对比
        装饰模式:
在不改变接口的前提下,动态扩展对象的访问;动态继承,让类具有在运行期改变行为的能力;装饰模式,突出的是运行期增加行为,这和继承是不同的,继承是在编译期增加行为强调:增强。
        代理模式:在不改变接口的前提下,控制对象的访问;从封装的角度讲,是为了解决类与类之间相互调用而由此导致的耦合关系,可以说是接口的另外一个层引用。比如:在 a 类->b 代理->c 类这个关系中,c 类的一切行为都隐藏在 b 中。即调用者不知道要访问的内容与代理了什么对象从复用的角度讲,可以解决不同类调用一个复杂类时,仅仅因较小的改变而导致整个复杂类新建一个类。比如:a 类->c 类 1;b 类->c 类 2。
        可以变为 a 类->ca 代理类->c 类;b 类->cb 代理类-c 类;代理模式,是类之间的封装和(某方面的)复用;强调:限制
5.常见架构部署设计
5.1.单机架构
        
系统业务量小,所有的代码都放在一个项目中,部署在一台服务器上;整个项目所有的服务都由这台服务器提供。
5.2.集群架构
        概念:
单机处理业务达到瓶颈,把单机复制几份构成集群;集群中每台服务器叫做这个集群的一个"节点",所有节点构成了一个集群。
5.2.1.单机和集群结构对比

5.2.2.集群架构特点
        
每个节点都提供相同的服务,这样系统处理能力就成倍(有多少个节点相当于提升了多少倍)提升。
5.2.3.集群架构问题
        用户的请求究竟由哪个服务器节点处理:我们能想到的是平均分布去访问服务器节点,平衡节点压力。
5.2.4.集群架构平衡节点压力解决方案
        中间件(负载均衡服务器)-"调度者"-nginx,有负载均衡服务器根据当前所有节点的负载情况,决定将这个请求交给哪个节点去处理。

  5.3.分布式微服架构
        背景
:当业务发展到一定程度的时候,会产生一个问题:无论怎么增加节点,整个集群性能的提升效果并不明显了。这个时候就需要微服架构了。
        概念:将一个完整系统按照业务功能拆分成一个个独立的子系统,在分布式结构中,每个子系统就被称为“服务。这些子系统能够独立运行在web容器中,子系统之间通过RPC方法进行同学
        集群和分布式侧重点:集群:同一个业务,部署在多个服务器上(多个人在一起做同样的事情)
分布式:一个业务拆分为多个子业务,部署在多个服务器上(多个人在一起做不同的事情)。
        设计原则:围绕业务;单一职责;谁创建,谁负责。
设计思路

 5.4.架构区别和联系
        集群架构主要的使用场景是为了分担请求的压力,在多个服务器部署相同的应用程序,来分担客户端请求,当压力进一步增大时(并发-访问量),假如有数据存储,Mysql的写压力增大,最后会崩溃,这时候引入分布式。
        分布式主要应用场景是单台机器已经无法满足这种性能的要求,必须要融合多个节点,且节点之间是有联系和交互的,相当于在写MySql时,每个节点存储部分数据。
        分布式是指多个系统协同合作完成一个特定任务的系统,解决了中心化管理的问题,把一个大的问题拆分成多个小的问题分别解决之,最终协同合作。分布式主要工作是分解任务-职能拆分。
        集群主要是简单加硬件机器解决问题,对于问题本身不做任何的分解;集群和分布式都是由多个节点组成,集群之间的通信协调基本是不需要的,但分布式各个节点间的通信协调必不可
少;将一套系统拆分成不同子系统部署在不同服务器上-分布式部署多个相同的子系统在不同的服务器上-集群部署在不同服务器上的同一个子系统-负载均衡。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值