内容纲要
软件系统设计及体系结构
第一章-软件设计模式基础
第二章-创建型设计模式
单例模式
介绍:为其它类
提供自己创建
的唯一
实例
-
实例
- 多线程共享打印机
- 多终端共享打印机
-
优点
- 减少内存开销
- 避免对资源的多重占用
-
缺点
- 没有接口,无法继承,与单一职责原则冲突
-
实例代码
//SingleObject.java package 专业课程.软件系统设计及体系结构.设计模式实例.单例模式; 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 单例模式"); } }
//SingletonPatternDemo.java package 专业课程.软件系统设计及体系结构.设计模式实例.单例模式; public class SingletonPatternDemo{ public static void main(String[] args) { //不合法的构造函数 //SingleObject() 是不可见的 //SingleObject object = new SingleObject(); //正确的构造方法,获取唯一可用的对象 SingleObject object = SingleObject.getInstance(); //显示消息 object.showMessage(); } }
-
多线程下的实现代码
-
懒汉式,线程不安全
延迟加载,在需要的时候才创建对象,在多线程下无法正常工作//饱汉式线程不安全 public class Singleton{ private static Singleton instance; //声明对象 private Singleton(){}; //构造方法 public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); //创建对象 } return instance; } }
-
懒汉式,线程安全
能够在多线程下正常工作,但是效率很低,现在的软件运行速度很快,一般不产生线程冲突,可判断程序是否会产生线程冲突而使用synchronized
关键字//饱汉式线程不安全 public class Singleton{ private static Singleton instance; //声明对象 private Singleton(){}; //构造方法 public static synchronized Singleton getInstance(){ if(instance == null){ instance = new Singleton(); //创建对象 } return instance; } }
-
饿汉式
类加载时就初始化类对象,浪费内存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 单例模式"); } }
-
工厂模式
在创建对象时不会对客户端暴露创建逻辑,通过使用一个共同的接口来指向新创建的对象。
-
介绍
- 意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行
- 主要作用:解决接口选择的问题
- 使用场景
- 日志记录器:本地硬盘、系统事件、远程服务器等
- 数据库访问
- 连接服务器的框架,三个协议:POP3、IMAP、HTTP
-
优点
- 调用者只需要知道名称
- 可拓展性高,增加产品只需拓展一个工厂类
- 屏蔽产品的具体实现,调用者只需关心产品的接口
-
缺点
- 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖
-
实现代码
//客户端类,用户只需要知道形状的标识符而不需要知道逻辑 public class FactoryPatternDemo{ public static void main(String[] args) { ShapeFactory shapeFactory = new ShapeFactory(); Shape shape1 = shapeFactory.getShape("CIRCLE"); shape1.draw(); Shape shape2 = shapeFactory.getShape("RECTANGLE"); shape2.draw(); Shape shape3 = shapeFactory.getShape("SQUARE"); shape3.draw(); } }
//工厂类,通过使用一个共同的接口来创建新的对象 public class ShapeFactory{ //使用getShape方法获取形状类型的对象 public Shape getShape(String shapeType){ if(shapeType == null) return null; if(shapeType.equalsIgnoreCase("CIRCLE")){ return new Circle(); } if(shapeType.equalsIgnoreCase("RECTANGLE")){ return new Rectangle(); } if(shapeType.equalsIgnoreCase("SQUARE")){ return new Square(); } return null; } }
//共用的接口类 public interface Shape{ void draw(); }
//圆形类 public class Circle implements Shape{ public Circle(){}; public void draw(){ System.out.println("Inside Circle::draw() method"); } } //矩形类 public class Rectangle implements Shape{ public Rectangle(){}; public void draw(){ System.out.println("Inside Rectangle::draw() method"); } } //正方形类 public class Square implements Shape{ public void draw(){ System.out.println("Inside Square::draw() method"); } }
-
抽象工厂
建造者模式(Builder Pattern)
使用多个简单的对象一步步构建成一个复杂的对象,提供了一种创建对象的最佳方式
一个Builder类会一步一步构造最终的对象,该Builder类是独立于其它对象的
- 介绍
- 意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示
- 主要解决:一个复杂对象的创建工作,其通常由各个部分的子对象用一定的算法构成;(由于需求变化,各个部位的对象经常面临剧烈变化,而将它们组合在一起的算法却相对稳定)
- 何时使用:一些基本部件不会变,而其组合经常变化的时候
- 应用实例:
- 肯德基:汉堡、可乐、薯条等对象是不变的,而其套餐组合是经常变化的
- Java中的StringBuilder
dad
第三章-结构型模式
适配器模式
-
概念
- 作为两个不兼容接口之间的桥梁,结合了两个独立接口的功能
- 也称为包装样式或者包装,将一个类的接口转换成用户所期待的
- 一个适配使得因接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中
-
介绍
- 主要解决:
- 在软件系统中,常常要将一些现存的对象放到新的环境中,而新环境要求的接口是现对象不能满足的
- 何时使用:
- 系统需要使用现有类,而此类接口不符合系统需要
- 想要建立一个可重复类,用于一些彼此之间无太大关系的类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口
- 通过接口转换,将一个类插入另一个类系中
- 应用实例:
- 电饭煲:日本电饭煲的电源接口标准是110V电压,而国内是220V,为使用日本电饭煲,需要一个电源适配器
- 主要解决:
-
实现代码
//测试程序 public class PlayerDemo { public static void main(String[] args) { AudioPlayer player = new AudioPlayer(); player.play("mp3","Only you.mp3"); player.play("vlc","Oh no.vlc"); player.play("mp4","Yes sir.mp4"); player.play("avi","Who am I.avi"); } }
//可播放mp3的接口 public interface MediaPlayer { void play(String audioType,String filename); } //可播放mp4和vlc格式的接口 public interface AdvancedPlayer { void play_mp4(String filename); void play_vlc(String filename); }
//AudioPlayer内置支持播放Mp3,适配后支持播放mp3和vlc public class AudioPlayer implements MediaPlayer { MediaAdapter mediaAdapter; @Override public void play(String audioType, String filename) { if (audioType.equalsIgnoreCase("mp3")) { System.out.println("Playing Mp3 file. Name:" + filename); } 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"); } } }
//实现Mp4和Vlc播放接口的类 public class Mp4Player implements AdvancedPlayer{ @Override public void play_mp4(String filename) { System.out.println("Playing Mp4 file. Name:"+filename); } @Override public void play_vlc(String filename) { //nothing } } public class VlcPlayer implements AdvancedPlayer{ @Override public void play_mp4(String filename) { //nothing to do } @Override public void play_vlc(String filename) { System.out.println("Playing Vlc file. Name: " + filename); } }
//适配 public class MediaAdapter implements MediaPlayer{ AdvancedPlayer advancedPlayer; public MediaAdapter(String audiotype){ if(audiotype.equalsIgnoreCase("vlc")){ advancedPlayer = new VlcPlayer(); }else if(audiotype.equalsIgnoreCase("mp4")){ advancedPlayer = new Mp4Player(); } } @Override public void play(String audioType, String filename) { if(audioType.equalsIgnoreCase("vlc")){ advancedPlayer.play_vlc(filename); }else if(audioType.equalsIgnoreCase("mp4")){ advancedPlayer.play_mp4(filename); } } }
组合模式
- 概念
- 为了一致对待容器节点和叶子节点,组合多个对象形成树形结构以表示具有整体-部分关系的层次结构,故称为组合模式
- 模式结构
Component
抽象构件,叶子构件和容器构件的接口或抽象类Leaf
叶子构件,叶子结点没有子结点Composite
容器构件,容器结点可以有子结点,子结点也可以为叶子构件
- 适用场景
- 在具有整体和部分的层级结构中,希望通过一种方式忽略整体和部分的差异,客户端可以一致地对待它们
- 在一个使用面向对象语言开发的系统中需要处理一个树形结构
- 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型
- 应用实例
- 公司职员的组织结构
-
实现代码
public class Employee { private String name; private String dept; private int salary; //叶子结点subordinate为空 //容器结点subordinate不为空 private List
subordinates; //构造函数 public Employee(String name,String dept,int salary){ this.name = name; this.dept = dept; this.salary = salary; subordinates = new ArrayList (); } public void add(Employee e){ subordinates.add(e); } public void remove(Employee e){ subordinates.remove(e); } public List getSubordinates(){ return subordinates; } public String toString(){ return ("Employee:[ Name: " + name + ",dept:"+dept+",salart:"+ salary+"]"); } } public class CompositionPatternDemo { public static void main(String[] args) { Employee CEO = new Employee("John","CEO",30000); Employee headSales = new Employee("Robert","Head Sales",20000); Employee headMarketing = new Employee("Michel","Head Marketing",20000); Employee clerk1 = new Employee("Laura","Marketing",10000); Employee clerk2 = new Employee("Bob","Marketing",10000); Employee salesExecutive1 = new Employee("Richard","Sales",10000); Employee salesExecutive2 = new Employee("Rob","Sales",10000); CEO.add(headSales); CEO.add(headMarketing); headSales.add(salesExecutive1); headSales.add(salesExecutive2); headMarketing.add(clerk1); headMarketing.add(clerk2); printEmployee(CEO); //递归输出层级结构 } //递归输出所有层级 static void printEmployee(Employee employee){ System.out.println(employee); for(Employee e:employee.getSubordinates()){ printEmployee(e); } } }
享元模式(Flyweight Pattern)
- 概念
- 主要用于减少创建对象的数量,以减少内存占用和提高性能
- 尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象
- 介绍
- 意图
- 运用共享技术有效地支持大量细粒度的对象
- 主要解决
- 在有大量对象时,可能会造成内存溢出,我们把其中共同的部分抽象出来
- 如果有相同的业务请求,直接返回早内存中已有的对象,避免重新创建
- 如何解决
- 用唯一标志码判断,如果在内存中有,则返回这个唯一标志码所标识的对象
- 使用场景
- 系统有大量相似对象
- 需要缓冲池的场景
- 意图
-
实例
通过享元模式减少创建的课本对象,以提供给指定数量的学生借阅-
Book接口类和Textbook类
public interface Book { //输出书本的状态信息 void showStatus(); } public class Textbook implements Book{ //书本名称 private String name; //该书的借阅次数 private int barrowNum; Textbook(String name){ this.name = name; barrowNum = 0; } //计书本的借阅次数 public void addBarrowNum(){ barrowNum++; } public void showStatus(){ System.out.println("书本的名称:《" + name + "》" +",被借阅的次数:" + barrowNum); } public void setName(String name) { this.name = name; } }
-
BookFactory工厂类。
提供所需的书本,区别于工厂模式,采用了HashMap的数据结构
如果哈希表中已经存在所需书本对象,则直接返回该对象;
若哈希表中不存在所需书本对象,则创建书本对象,以此来达到减少创建对象的目的。public class BookFactory { //哈希表中存储所有的对象 //区别于工厂模式,用哈希表减少创建对象的数量 private static final HashMap
bookMap = new HashMap (); public static Book getTextBook(String name){ //先在哈希表中查找有没有已存在的课本对象 Textbook textbook = (Textbook)bookMap.get(name); if(textbook == null){ //没有则新建 textbook = new Textbook(name); bookMap.put(name,textbook); System.out.println("书库中不存在,为您订购了一本书:<<" + name + ">>"); } //计该书的借阅次数 textbook.addBarrowNum(); return textbook; } } -
LibraryDemo 测试主类
public class ShapeFlyweightDemo { private static final String colors[] = {"Red","Green","Blue","White","Black"}; public static void main(String[] args) { for (int i = 0; i < 20; ++i){ Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(100); circle.draw(); } } //返回随机的颜色字符串 private static String getRandomColor(){ return colors[(int)(Math.random()*colors.length)]; } private static int getRandomX(){ return (int)(Math.random()*100); } private static int getRandomY(){ return (int)(Math.random()*100); } }
-