[知识点复习]软件体系结构与设计模式

感谢我院金福生老师的辛勤教学!
做笔记的时候类图大部分是从网络中找的, 很杂, 如不小心侵权, 请联系本人orz

软件体系结构与设计模式

大纲

1.基本概念

  • 软件体系结构
  • 设计模式
  • 非功能需求以及含义
  • 编程的三个层次/境界
  • 设计模式的六大原则
  • 面向对象设计的六大原则(举例)

2. 设计模式

  • 观察者
  • MVC(时序图)
  • 策略
  • 适配器
  • 单例
  • 代理
  • 工厂/抽象工厂(产品层级,产品族)
  • 装饰着
  • 命令
  • 访问者

3. 软件体系结构

  • 分层的风格
  • 管道过滤器风格
  • 主子程序风格
  • 面向对象风格
  • 基于共享数据的事件风格

集成开发环境
结合监听器理解时间风格

基本概念

1. 软件体系结构
  1. 软件体系结构 = (元素,形态,基本理论)
    软件能体系结构是一组具有特定结构的设计元素(处理元素、数据元素、连接元素)。
  2. 软件体系结构涉及 软件高层的设计和实现,通过 组装 一定数量的具有良好形态的 元素,以 满足 主要的 功能和性能需求
  3. 定义了组成系统的计算机构件和构件之间的相互关系。
    • 体系结构层次的设计:
      • 组成系统的构件描述
      • 构件之间的交互
      • 指导构件交互的模式
      • 施加在模式上的约束
  4. 是一个系统的结构,包括软件构件、构件的外部可见属性、构件关系
    • 外部可见属性:其他构件可以对该构件做的假定(性能特性、错误处理、共享资源的使用等)
  5. 关注使用、功能、性能、弹性、复用、可理解性、经济和技术约束与折衷、审美考虑
  6. (IEEE)定义了组成系统的
    • 构件(实施计算、保存状态)
    • 连接件(表达构件之间的关系)
    • 他们之间的匹配(表示系统的拓扑结构)
  • 为什么要用软件体系结构
    • 随着软件规模和复杂度的增加,设计问题已经超越了算法和数据结构
    • 设计和描述系统的总体结构成为一类新问题
2. 设计模式

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

3. 非功能需求、含义
  1. 性能
  2. 可拓展性/伸缩性
  3. 可维护性
  4. 可用性
  5. 安全性
  6. 业务质量
4. 编程的三个境界(层次)
  1. 针对实现编程
Dog d = new Dog();
d.bark();
  1. 针对接口编程 | 超类型编程
Animal animal = new Dog();
animal.makesound();
  1. 在运行时才指定实现的对象
a = getAnimal();
a.makesound();
5. 设计模式的六大原则
  1. 单一原则
    • 一个类只负责一项职责
    • 业务对象(BO)、业务逻辑(BL)拆分
  2. 里氏替换原则(LSP)
    • 子类可以拓展父类的功能,但不能改变原有父类的功能
    • (目的:增强健壮性)实际项目中,每个子类对应不同的业务含义,使父类作为参数传递不同的子类完成不同的业务逻辑
  3. 依赖倒置原则
    • 面向接口编程;(通过接口作为参数实现应用场景),抽象就是接口或抽象类,细节就是实现类;
    • 上层模块不应该依赖下层模块,两者皆依赖其抽象;细节依赖抽象
      接口负责定义public属性和方法,并且申明与其他对象的依赖关系。抽象类负责公共部分的实现,实现类准确的业务逻辑
  4. 接口隔离
    • 建立单一接口;(扩展为类也是一种接口,一切皆接口)
      a. 客户端不应该依赖他不需要的接口;
      b. 类之间的依赖关系应该建立在最小的接口上
      接口的设计粒度越小,系统越灵活,但是灵活的同时结构复杂性提供,开发难度变大,维护性降低
  5. 迪米特原则
    • 最少知道原则,尽量降低类与类之间的耦合;一个对象应该对其他对象有最少的了解
  6. 开闭原则
    • 用抽象构件架构,用实现扩展原则
6. 面向对象设计的六大原则
  1. 封装变化
  2. 多用组合少用继承
  3. 针对接口编程,不针对实现
  4. 追求交互对象之间的松耦合
  5. 类对拓展开放,对修改关闭
  6. 依赖抽象,不依赖具体类

2. 设计模式

1. 观察者

对象之间存在一对多关系时使用。譬如当一个对象被修改时会自动通知其依赖对象

  • 关键:在抽象类里有一个arrayList存放观察者们
  • 例如:
    1. 拍卖师观察价格,通知竞价者竞价,竞价者是观察者,拍卖师给出的价格变化,竞价者也做出行动
  • 优点
    1. 观察者和被观察者是抽象耦合的
    2. 建立了一套触发机制
  • 缺点:
    1. 如果被观察者有很多个直接或间接的观察者,被观察者发生变化要通知到所有观察者将花费大量时间
    2. 如果被观察对象和观察者之间有循环依赖,观察目标会触发他们之间的循环调用,可能引起系统崩溃
    3. 观察者模式没有相应的机制让观察者知道被观察对象是如何变化的

观察者模式


Subject.java:
public class Subject {
   
   private List<Observer> observers 
      = new ArrayList<Observer>();
   private int state;
 
   public int getState() {
      return state;
   }
 
   public void setState(int state) {
      this.state = state;
      notifyAllObservers();
   }
 
   public void attach(Observer observer){
      observers.add(observer);      
   }
 
   public void notifyAllObservers(){
      for (Observer observer : observers) {
         observer.update();
      }
   }  
}
-----------------------------
ObserverPatternDemo.java:
public class ObserverPatternDemo {
   public static void main(String[] args) {
      Subject subject = new Subject();
 
      new HexaObserver(subject);
      new OctalObserver(subject);
      new BinaryObserver(subject);
 
      System.out.println("First state change: 15");   
      subject.setState(15);
      System.out.println("Second state change: 10");  
      subject.setState(10);
   }
}
------------------------------
HexaObserver.java:
public class HexaObserver extends Observer{
 
   public HexaObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }
 
   @Override
   public void update() {
      System.out.println( "Hex String: " 
      + Integer.toHexString( subject.getState() ).toUpperCase() ); 
   }
}

2. MVC(时序图)

模型(存取数据的对象,可以具有逻辑,在数据变化时更新控制器)-视图(模型包含数据的可视化)-控制器(作用在模型和视图上,控制数据流向模型、在数据变化时更新视图,使视图与模型分隔开)

在这里插入图片描述

测试类:
public class MVCPatternDemo {
   public static void main(String[] args) {
 
      //从数据库获取学生记录
      Student model  = retrieveStudentFromDatabase();
 
      //创建一个视图:把学生详细信息输出到控制台
      StudentView view = new StudentView();
 
      StudentController controller = new StudentController(model, view);
 
      controller.updateView();
 
      //更新模型数据
      controller.setStudentName("John");
 
      controller.updateView();
   }
 
   private static Student retrieveStudentFromDatabase(){
      Student student = new Student();
      student.setName("Robert");
      student.setRollNo("10");
      return student;
   }
}

3. 策略

定义一系列算法并把它们封装起来,使他们可以相互替换。在策略模式中,一个类的行为或算法可以在运行时更改。如果一个系统中有许多类,其区别仅在于它们的行为,或者系统需要在几种算法中选择其中一种,就可以使用策略模式。

  • 例如:
    1. 出游方式:自行车、自驾游、坐火车,每一种方式都是一个策略
  • 优点:
    1. 算法可以自由切换
    2. 避免多重条件判断
    3. 扩展性良好
  • 缺点:
    1. 策略类增多
    2. 所有策略类都要暴露出来

策略模式

接口:
public interface Strategy {
   public int doOperation(int num1, int num2);
}

实现接口的实体类:
public class OperationAdd implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 + num2;
   }
}

context类:
public class Context {
   private Strategy strategy;
 
   public Context(Strategy strategy){
      this.strategy = strategy;
   }
 
   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}

测试结果:
public class StrategyPatternDemo {
   public static void main(String[] args) {
      Context context = new Context(new OperationAdd());    
      System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
 
      context = new Context(new OperationSubstract());      
      System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
 
      context = new Context(new OperationMultiply());    
      System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
   }
}

4. 适配器

适配器模式将一个接口转换成客户需要的另一个接口。使得由于接口不兼容而不能一起工作的那些类可以一起工作。

  • 关键:适配器继承或依赖已有的对象,实现目标接口
  • 优点:
    1. 可以让两个没有关联的类一起运行
    2. 提高类复用性
    3. 增加类的透明度
    4. 灵活性好
  • 缺点:
    1. 过多使用适配器会让系统非常零乱,不宜整体进行把握。譬如:明明看到调用a的接口,但是其内部是b接口的实现
    2. 受java继承机制的影响,最多只能适配一个抽象适配者类
  • 分类:对象适配器,类适配器(多重继承)
适配器装饰者
匹配法则转换接口添加功能
代码修改允许客户使用新的库和子集合允许新行为加到类中而无需修改代码

适配器

创建播放器的接口
public interface MediaPlayer {
   public void play(String audioType, String fileName);
}
public interface AdvancedMediaPlayer { 
   public void playVlc(String fileName);
   public void playMp4(String fileName);
}

advance接口的实现类:
public class VlcPlayer implements AdvancedMediaPlayer{
   @Override
   public void playVlc(String fileName) {
      System.out.println("Playing vlc file. Name: "+ fileName);      
   }
 
   @Override
   public void playMp4(String fileName) {
      //什么也不做
   }
}
public class MediaAdapter implements MediaPlayer {
 
   AdvancedMediaPlayer advancedMusicPlayer;
 
   public MediaAdapter(String audioType){
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();       
      } else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }  
   }
 
   @Override
   public void play(String audioType, String fileName) {
      if(audioType.equalsIgnoreCase("vlc")){
         advancedMusicPlayer.playVlc(fileName);
      }else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}

另一个接口的适配器类
public class MediaAdapter implements MediaPlayer {
 
   AdvancedMediaPlayer advancedMusicPlayer;
 
   public MediaAdapter(String audioType){
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();       
      } else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }  
   }
 
   @Override
   public void play(String audioType, String fileName) {
      if(audioType.equalsIgnoreCase("vlc")){
         advancedMusicPlayer.playVlc(fileName);
      }else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}

另一个接口的实体类
public class AudioPlayer implements MediaPlayer {
   MediaAdapter mediaAdapter; 
 
   @Override
   public void play(String audioType, String fileName) {    
 
      //播放 mp3 音乐文件的内置支持
      if(audioType.equalsIgnoreCase("mp3")){
         System.out.println("Playing mp3 file. Name: "+ fileName);         
      } 
      //mediaAdapter 提供了播放其他文件格式的支持
      else if(audioType.equalsIgnoreCase("vlc") 
         || audioType.equalsIgnoreCase("mp4")){
         mediaAdapter = new MediaAdapter(audioType);
         mediaAdapter.play(audioType, fileName);
      }
      else{
         System.out.println("Invalid media. "+
            audioType + " format not supported");
      }
   }   
}

测试
public class AdapterPatternDemo {
   public static void main(String[] args) {
      AudioPlayer audioPlayer = new AudioPlayer();
 
      audioPlayer.play("mp3", "beyond the horizon.mp3");
      audioPlayer.play("mp4", "alone.mp4");
      audioPlayer.play("vlc", "far far away.vlc");
      audioPlayer.play("avi", "mind me.avi");
   }
}

5. 单例

涉及到一个单一的类,该类负责创建自己的对象,同时确保只有一个对象被创建,可直接访问不需要实例化.

  • 注意:
    1. 单例模式只有一个实例
    2. 单例模式的类必须自己创建自己的唯一实例
    3. 必须向其他对象提供这一实例
  • 优点:
    1. 在内存里只有一个实例,减少了内存的开销
    2. 避免对资源的多重占用
  • 缺点:
    1. 没有接口,不能继承,与单一职责原则冲突
    2. 只关心其内部逻辑,不关心外部的实例化

单例

public class SingleObject {
 
   //创建 SingleObject 的一个对象
   private static SingleObject instance = new SingleObject();
 
   //让构造函数为 private,这样该类就不会被实例化
   private SingleObject(){}
 
   //获取唯一可用的对象
   public static SingleObject getInstance(){
      return instance;
   }
 
   public void showMessage(){
      System.out.println("Hello World!");
   }
}

测试
public class SingletonPatternDemo {
   public static void main(String[] args) {
 
      //不合法的构造函数
      //编译时错误:构造函数 SingleObject() 是不可见的
      //SingleObject object = new SingleObject();
 
      //获取唯一可用的对象
      SingleObject object = SingleObject.getInstance();
 
      //显示消息
      object.showMessage();
   }
}

若两个进程同时运行getInstance(),可能会创建多个实例引发错误,解决:

  1. getInstance()变成同步:public static synchronized Singleton getInstance(){...}
  2. 急切创建实例
public class Singleton{
    private static Singleton _instance = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return _instance;
    }
}
  1. 双重检查枷锁

public static Singleton getInstance(){
    if(_instance == NULL){
        synchronized(Singleton.class){
            if(_instance == NULL){
                _instance = new Singleton();
            }
        }
    }
    return _instance;
}

6. 代理

一个类代表另一个类的功能.为其他对象提供一种代理,控制对这个对象的访问

  • 例如:猪八戒去高老庄找高翠兰,把高翠兰的外貌抽象成接口,悟空和高翠兰都实现了这个接口.猪八戒访问高翠兰的时候看不出来这是悟空,可以说,悟空是高翠兰的代理

  • 优点:

    1. 职责清晰
    2. 高拓展性
    3. 智能化
  • 缺点:

    1. 由于客户和功能的实现类之间增加了代理,可能造成请求的处理速度变慢.
    2. 实现代理需要额外的工作,增加了代码的复杂度

代理模式

(使用代理类减少加载图像的内存占用)

创建一接口
public interface Image {
   void display();
}

创建接口实现类(包括代理者和真正实现者)
public class RealImage implements Image {
 
   private String fileName;
 
   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }
 
   @Override
   public void display() {
      System.out.println("Displaying " + fileName);
   }
 
   private void loadFromDisk(String fileName){
      System.out.println("Loading " + fileName);
   }
}
// 代理者
public class ProxyImage implements Image{
 
   private RealImage realImage;
   private String fileName;
 
   public ProxyImage(String fileName){
      this.fileName = fileName;
   }
 
   @Override
   public void display() {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }
}

测试:
public class ProxyPatternDemo {
   
   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");
 
      // 图像将从磁盘加载
      image.display(); 
      System.out.println("");
      // 图像不需要从磁盘加载
      image.display();  
   }
}

7. 工厂

这个模式不会向客户端暴露创建的逻辑,仅使用共同的接口指向创建的对象.定义一个创建对象的接口,让子类自己决定实例化哪一个工厂类,创建过程延迟到子类进行

  • 关键: 创建过程在子类进行
  • 优点:
    1. 想要创建一个对象,只需要知道其名字就可以了
    2. 可扩展性高,增加一个新产品,只需要扩展一个新的工厂类就可以
    3. 创造过程对客户隐藏,调用者只关心产品接口
  • 缺点:
    1. 每增加一个产品都需要增加一个具体类和一个对象实现工厂,增加了类的个数,系统复杂度和类之间的依赖也增加

工厂模式

创建一个接口
public interface Shape {
   void draw();
}

创建接口的实现类
public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

创建一个工厂
public class ShapeFactory {
    
   //使用 getShape 方法获取形状类型的对象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }
      return null;
   }
}

测试
public class FactoryPatternDemo {
 
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();
 
      //获取 Circle 的对象,并调用它的 draw 方法
      Shape shape1 = shapeFactory.getShape("CIRCLE");
 
      //调用 Circle 的 draw 方法
      shape1.draw();
 
      //获取 Rectangle 的对象,并调用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
 
      //调用 Rectangle 的 draw 方法
      shape2.draw();
 
      //获取 Square 的对象,并调用它的 draw 方法
      Shape shape3 = shapeFactory.getShape("SQUARE");
 
      //调用 Square 的 draw 方法
      shape3.draw();
   }
}

8. 抽象工厂(产品层级,产品族)

抽象工厂可以看作其他工厂的工厂,接口负责创建相关对象的工厂,不需要指定具体的类,每个生成的工厂都按照工厂模式提供对象

  • 关键: 一个工厂里聚合多个同类产品
  • 优点:
    1. 当一个产品族中的多个对象被设定为一起工作时,可以保证客户端始终只用同一个产品族中的对象
  • 缺点:
    1. 扩展困难,要增加一个新的产品,需要在产品族和具体类中都加代码

在这里插入图片描述

测试:
public class AbstractFactoryPatternDemo {
   public static void main(String[] args) {
 
      //获取形状工厂
      AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
      //获取形状为 Circle 的对象
      Shape shape1 = shapeFactory.getShape("CIRCLE");
      //调用 Circle 的 draw 方法
      shape1.draw();
      //获取形状为 Rectangle 的对象
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
      //调用 Rectangle 的 draw 方法
      shape2.draw();
      //获取形状为 Square 的对象
      Shape shape3 = shapeFactory.getShape("SQUARE");
      //调用 Square 的 draw 方法
      shape3.draw();
 
      //获取颜色工厂
      AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR"); 
      //获取颜色为 Red 的对象
      Color color1 = colorFactory.getColor("RED");
      //调用 Red 的 fill 方法
      color1.fill();
      //获取颜色为 Green 的对象
      Color color2 = colorFactory.getColor("Green");
      //调用 Green 的 fill 方法
      color2.fill();
      //获取颜色为 Blue 的对象
      Color color3 = colorFactory.getColor("BLUE");
      //调用 Blue 的 fill 方法
      color3.fill();
   }
}

9. 装饰者

装饰者允许向一个类添加新的功能又不改变其结构,创建一个装饰类用来包装原有的类,在保持类的方法签名完整性的前提下添加了新的功能

  • 关键:
    1. componet类定义为抽象
    2. 修饰类引用和继承componet,具体拓展类重写父类的方法
  • 优点
    1. 装饰类和被装饰类可以独立发展,不会相互耦合
  • 缺点:
    1. 多层装饰实现比较复杂

在这里插入图片描述

创建一接口
public interface Shape {
   void draw();
}

创建接口一实现类
public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Shape: Rectangle");
   }
}

创建抽象装饰类
public abstract class ShapeDecorator implements Shape {
   protected Shape decoratedShape;
 
   public ShapeDecorator(Shape decoratedShape){
      this.decoratedShape = decoratedShape;
   }
 
   public void draw(){
      decoratedShape.draw();
   }  
}

创建实体装饰类
public class RedShapeDecorator extends ShapeDecorator {
 
   public RedShapeDecorator(Shape decoratedShape) {
      super(decoratedShape);     
   }
 
   @Override
   public void draw() {
      decoratedShape.draw();         
      setRedBorder(decoratedShape);
   }
 
   private void setRedBorder(Shape decoratedShape){
      System.out.println("Border Color: Red");
   }
}

测试:
public class DecoratorPatternDemo {
   public static void main(String[] args) {
 
      Shape circle = new Circle();
      ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
      ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
      //Shape redCircle = new RedShapeDecorator(new Circle());
      //Shape redRectangle = new RedShapeDecorator(new Rectangle());
      System.out.println("Circle with normal border");
      circle.draw();
 
      System.out.println("\nCircle of red border");
      redCircle.draw();
 
      System.out.println("\nRectangle of red border");
      redRectangle.draw();
   }
}

10. 命令

将一个请求封装成一个对象,传给调用对象,调用对象寻找可以处理该命令的合适对象并传命令给他,让他执行

  • 关键:三个对象:received真正执行命令的对象;command;invoker调用命令对象的入口
  • 优点:
    1. 降低系统耦合度
    2. 新的命令很容易加到系统中
  • 缺点:
    1. 可能导致某些系统有过多的具体命令类

在这里插入图片描述

创建命令接口
public interface Order {
   void execute();
}

创建命令接口的实现类
public class BuyStock implements Order {
   private Stock abcStock;
 
   public BuyStock(Stock abcStock){
      this.abcStock = abcStock;
   }
 
   public void execute() {
      abcStock.buy();
   }
}

创建请求类
public class Stock {
   
   private String name = "ABC";
   private int quantity = 10;
 
   public void buy(){
      System.out.println("Stock [ Name: "+name+", 
         Quantity: " + quantity +" ] bought");
   }
   public void sell(){
      System.out.println("Stock [ Name: "+name+", 
         Quantity: " + quantity +" ] sold");
   }
}

创建命令调用类
public class Broker {
   private List<Order> orderList = new ArrayList<Order>(); 
 
   public void takeOrder(Order order){
      orderList.add(order);      
   }
 
   public void placeOrders(){
      for (Order order : orderList) {
         order.execute();
      }
      orderList.clear();
   }
}

测试:
public class CommandPatternDemo {
   public static void main(String[] args) {
      Stock abcStock = new Stock();
 
      BuyStock buyStockOrder = new BuyStock(abcStock);
      SellStock sellStockOrder = new SellStock(abcStock);
 
      Broker broker = new Broker();
      broker.takeOrder(buyStockOrder);
      broker.takeOrder(sellStockOrder);
 
      broker.placeOrders();
   }
}

11. 访问者

使用访问者类改变元素的执行算法,使其可以随着访问者的改变而改变

  • 关键:在数据基础类里有一个方法接受访问者,并将自身作为参数传给访问者
  • 优点:
    1. 单一职责
    2. 扩展性
    3. 灵活性
  • 缺点:
    1. 具体元素对访问者公布细节,违反迪米特原则
    2. 依赖了具体类,违反依赖倒置原则
    3. 具体元素变更困难

在这里插入图片描述

创建表示元素的接口
public interface ComputerPart {
   public void accept(ComputerPartVisitor computerPartVisitor);
}

创建元素的实体类
public class Keyboard  implements ComputerPart {
 
   @Override
   public void accept(ComputerPartVisitor computerPartVisitor) {
      computerPartVisitor.visit(this);
   }
}

创建访问者接口
public interface ComputerPartVisitor {
   public void visit(Computer computer);
   public void visit(Mouse mouse);
   public void visit(Keyboard keyboard);
   public void visit(Monitor monitor);
}

创建实现了访问者类的访问者
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
 
   @Override
   public void visit(Computer computer) {
      System.out.println("Displaying Computer.");
   }
 
   @Override
   public void visit(Mouse mouse) {
      System.out.println("Displaying Mouse.");
   }
 
   @Override
   public void visit(Keyboard keyboard) {
      System.out.println("Displaying Keyboard.");
   }
 
   @Override
   public void visit(Monitor monitor) {
      System.out.println("Displaying Monitor.");
   }
}

测试:
public class VisitorPatternDemo {
   public static void main(String[] args) {
 
      ComputerPart computer = new Computer();
      computer.accept(new ComputerPartDisplayVisitor());
   }
}

软件体系结构

1. 分层的风格

  • 优点:
    1. 支持基于抽象程度递增的系统设计,使设计者可以把一个复杂系统按递增的步骤分解
    2. 支持功能增强,功能的改变最多影响相邻上下层
    3. 支持重用,只要上下层的接口不变,同一层的不同实现可以交换使用.
  • 缺点:
    1. 并不是每个系统都可以容易的划分为几个层次
    2. 很难找到一个合适的,正确的层次抽象方法

2. 管道过滤器风格

filter必须是独立的实体,不了解数据的来源和去向

  • 优点:
    1. 输入输出更容易理解,过程更直观
    2. 良好的复用支持
    3. 良好的可维护性和可增强性
    4. 允许某些专业分析(吞吐量等)
    5. 允许并发执行
  • 缺点:
    1. 容易导致批处理方式,不适合交互式系统
    2. filter多余的解析过程会降低性能,增加复杂度
    3. 有时必须维护两个分离又相关的流间对应关系
    4. filter之间传输效率低

3. 主子程序风格

  • 优点:
    1. 任务分解成多个易于控制和处理的子程序
    2. 便于开发和维护
    3. 适用于较大程序
  • 缺点:
    1. 规模
    2. 可重用性差,数据安全性差
    3. 把数据和处理过程分离,数据结构改变时,所有相关的结构都要跟着改变

4. 面向对象风格

  • 优点:
    1. 高度模块化,改变一个不影响其他
    2. 封装功能,功能和细节装在对象中,只需调用接口
    3. 代码重用
    4. 灵活
    5. 易维护,接近人的思维,易于理解
  • 缺点:
    1. 对象的调用需要知道标识符
    2. 不同对象对同一对象的调用可能相互影响

5. 基于共享数据的事件风格

  • 优点:
    1. 支持复用,构件通过登记感兴趣的事件被引入系统
    2. 便于系统变化,构件可容易的升级更换
    3. 无需事先设定调用顺序
    4. 异步执行
  • 缺点:
    1. 系统行为难以控制
    2. 有时需要一个共享数据仓库进行交互,影响系统性能
    3. 系统验证和调试成问题
  • 10
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值