admin管理员组

文章数量:1530080

七个设计原则

设计原则核心思想:
    1) 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
    2) 针对接口编程,而不是针对实现编程。
    3) 为了交互对象之间的松耦合设计而努力

单一职责原则

定义:
	就一个类而言,应该只有一个引起它变化的原因
理解:
	对于相同的功能,不要散落在各个类中(内聚性)
	一个类的职责单一(低耦合)

接口隔离原则

定义:
	客户端不应该依赖它不需要的接口
重构:
	把接口细分为更小的接口

依赖倒转原则

定义
	高层模块不应该依赖低层模块,二者都应该依赖其抽象
	抽象不应该依赖细节,细节应该依赖抽象
依赖体现:
	调用、继承、实现

里氏替换原则

定义:
	子类型必须能够替换父类型,且功能保持不变;尽量不重写,重载父类方法,来改变程序功能

开闭原则

定义:
	一个软件实体应该对扩展开放,对修改关闭
理解:
	满足客户新的需求扩展功能
	扩展同时不修改原有代码
实现关键:
	抽象(抽象类、接口)
实现方法:
	对于发生变化的功能进行抽象形成接口,给接口以不同实现
	模块间的调用通过接口进行

迪米特法则

定义:
	一个对象应该对其他对象保持最少的了解
	只与它的直接朋友通信
朋友:
	两个对象之间存在耦合关系称之为直接朋友,局部变量不是直接朋友

合成复用原则

定义:
	尽量少用继承,多用组合聚合实现复用

23种设计模式

创建型模式 : 单例模式 , 抽象工厂模式 , 原型模式 , 建造者模式 , 工厂模式

结构型模式 : 适配器模式 , 桥接模式 , 装饰模式 , 组合模式 , 外观模式 , 享元模式 , 代理模式

行为型模式 : 模板方法模式 , 命令模式 , 访问者模式 , 迭代器模式 , 观察者模式 , 中介者模式 , 备忘录模式 , 解释器模式 , 状态模式 , 策略模式 , 职责链模式

创建型设计模式

创建型模式 : 单例模式 , 抽象工厂模式 , 原型模式 , 建造者模式 , 工厂模式

单例模式

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)

饿汉式(静态常量)应用实例 步骤如下:

  1. 构造器私有化 (防止 new )

  2. 类的内部创建对象

  3. 向外暴露一个静态的公共方法getInstance ();

  4. 代码实现

单例模式注意事项和细节说明

  • 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
  • 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
  • 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)
//但是可能造成内存浪费
//单例模式:饿汉式(静态常量)
public class StaticChangLiang {
    private final static StaticChangLiang instance = new StaticChangLiang();

    //提供私有的构造器,防止被new对象
    private StaticChangLiang() {
    }

    //提供静态公共方法,以便于其他类使用
    public static StaticChangLiang getInstance() {
        return instance;
    }
}
//单例模式:懒汉式(线程不安全),但是只能在单线程下使用.在多线程环境下不可使用这种方式 
public class UnSafe {
    private static UnSafe instance;

    private UnSafe() {
    }
    //只有在调用getInstance()方法时,才创建单例对象,饿汉式
    public static UnSafe getInstance() {
    //判断如果是空的说明第一次创建,就创建其实例赋值给成员变量
        if (instance == null) {
            instance = new UnSafe();
        }
        return instance;
    }
}//结论:在实际开发中,不要使用这种方式.
//懒汉式(线程安全)
public class Safe {
    private static Safe safe;

    private Safe() {
    }
    //加入同步代码,线程安全,同步方法,解决了线程不安全问题 
    public static synchronized Safe getInstance() {
        if (safe == null) {
            safe = new Safe();
        }
        return safe;
    }
}
 //效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例, 直接return就行了。方法进行同步效率太低
//单例模式双重检查   线程安全;延迟加载;效率较高 
public class XianChengSafe {
    private static XianChengSafe xcs;

    public static synchronized XianChengSafe getInstance(){
        //ABCDE...多个线程
        if (xcs==null){
            synchronized (XianChengSafe.class){
                //A线程执行完并实例化后,B线程就会到这里,由于此时xcs已经不为空就直接跳过if
                if (xcs==null){
                    //A线程最先进入到这里
                    synchronized (XianChengSafe.class){
                        xcs = new XianChengSafe();
                    }
                }
            }
        }
        return xcs;
    }
}
/*
单例模式(静态内存类) 线程安全的,采用了类装载的机制来保证初始化实例时只有一个线程。
静态内部类方式在StaticSafe类被装载时并不会立即实例化,而是在需要实例化时,
调用getInstance方法,才会装载StaticSafeInstance类,从而完成StaticSafe的实例化
*/
public class StaticSafe {

    private StaticSafe(){

    }
    //提供一个私有的静态内部类
    private static class StaticSafeInstance{
        private final static StaticSafe instance = new StaticSafe();
    }

    public static StaticSafe getInstance(){
        return StaticSafeInstance.instance;
    }
}
//枚举:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象
public enum Singleton {
    INSTANCE;
    public void method(){
        System.out.println("hello!");
    }
}
工厂模式

抽象工厂,在超类中通过自身的getFactory(String type)获得子类

一、有一个OEM制造商代理做HP笔记本(Laptop),后来该制造商得到了更多的品牌笔记本电脑的订单Acer,Lenovo,Dell,该OEM商发现,如果一次同时做很多个牌子的本本,有些不利于管理。利用工厂模式改善设计,用java控制台应用程序实现该OEM制造商的工厂模式。

UML类图

//工厂方法模式
public class FactoryMethod {
	public static void main(String[] args) {
		Computer c = null;
		Factory f = null;
		f = new DellFactory();
		c = f.getComputerType();
		c.ComputerType();
		f = new LenovoFactory();
		c = f.getComputerType();
		c.ComputerType();
		f = new AcerFactory();
		c = f.getComputerType();
		c.ComputerType();
	}
}
 
interface Factory{
	Computer getComputerType();
}
 
class DellFactory implements Factory{
	@Override
	public Computer getComputerType() {
		return new Dell();
	}
}
 
class AcerFactory implements Factory{
	@Override
	public Computer getComputerType() {
		return new Acer();
	}
}
 
class LenovoFactory implements Factory{
	@Override
	public Computer getComputerType() {
		return new Lenovo();
	}
}
 
interface Computer{
	public void ComputerType();
}
 
class Dell implements Computer{
	@Override
	public void ComputerType() {
		System.out.println("Dell Computer");	
	}
}
 
class Acer implements Computer{
 
	@Override
	public void ComputerType() {
		System.out.println("Acer Computer");	
	}
}

class Lenovo implements Computer{
	@Override
	public void ComputerType() {
		System.out.println("Lenovo Computer");	
	}
}

二、下图设计类图是关于游戏软件的设计

在该设计中,SlowGameFactory类负责创建SlowFighter对象与SlowMonster对象,并且将创建完的对象以其超类类型返回给ClientGUI对象。然后,ClientGUI对象将操纵SlowFighter对象与SlowMonster对象,使得它们互相打斗

1、上述设计使用了什么设计模式?
抽象工厂设计模式

2、请在以上设计类图中添加4个新的类MedFighter、SuperFighter、MedMonster和SuperMonster,以便使得MedFighter对象能够对应于MedMonster对象;SuperFighter对象能够对应于SuperMonster对象,绘制新设计类图;

3、除了以上添加的4个类以外,在以上类图中还应该添加什么类?
SuperGameFactory MedGameFactory

4、描述新的设计类图;
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类
一个抽象工厂类,可以派生出多个具体工厂类
每个具体工厂类可以创建多个具体产品类的实例,也就是创建的是一个产品线下的多个产品

5、明确说明新设计的优点。
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个

一个农场专门负责培育各种水果,有葡萄,草莓和苹果,类图如下,请按以下要求完 成水果生长状态的描述

1、使用简单工厂模式,绘制系统完整类图,完成对象的创建

2、编写工厂类和客户端主程序,并在主程序中完成草莓生长状态的描述

//SimpleFruitFactory.java
public class SimpleFruitFactory {
    public static Fruit getFruit(String type) {
        Fruit fruit = null;
        if (type.equals("Apple"))
            return new Apple();
        else if (type.equals("Grape"))
            return new Grape();
        else if (type.equals("Strawberry"))
            return new Strawberry();
        else
            return fruit;
    }
}
//Fruit.java
public interface Fruit {
    public void plant();
    public void grow();
    public void harvest();
}
//Apple.java
public class Apple implements Fruit{
    @Override
    public void plant() {
        System.out.println("apple is planting...");
    }
    @Override
    public void grow() {
        System.out.println("apple is growing...");
    }
    @Override
    public void harvest() {
        System.out.println("apple is harversting...");
    }
}
//Grape.java
public class Grape implements Fruit{
    @Override
    public void plant() {
        System.out.println("grape is planting...");
    }
    @Override
    public void grow() {
        System.out.println("grape is growing...");
    }
    @Override
    public void harvest() {
        System.out.println("grape is harversting...");
    }
}
//Strawberry.java
public class Strawberry implements Fruit{
    @Override
    public void plant() {
        System.out.println("strawberry is planting...");
    }
    @Override
    public void grow() {
        System.out.println("strawberry is planting...");
    }
    @Override
    public void harvest() {
        System.out.println("strawberry is planting...");
    }
}
//Client.java
public class Client {
    public static void main(String[] args) {
        Fruit f = SimpleFruitFactory.getFruit("Apple");
        f.plant();
        f.grow();
        f.harvest();
    }
}
建造者模式
  1. 建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。

  2. 建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。

建造者模式的四个角色

  1. Product(产品角色): 一个具体的产品对象。
  2. Builder(抽象建造者): 创建一个Product对象的各个部件指定的 接口/抽象类。
  3. ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。
  4. Director(指挥者): 构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。

一般类图:超类可以是接口或者抽象类

下面为一个盖房子案例

需要建房子:这一过程为打桩、砌墙、封顶。不管是普通房子也好,高楼建筑也好都
需要经历这些过程,我们使用建造者模式完成

//产品类
public class House {
	private String baise;//地基
	private String wall;//墙
	private String roofed;//屋顶
	
	public String getBaise() {
		return baise;
	}
	public void setBaise(String baise) {
		this.baise = baise;
	}
	public String getWall() {
		return wall;
	}
	public void setWall(String wall) {
		this.wall = wall;
	}
	public String getRoofed() {
		return roofed;
	}
	public void setRoofed(String roofed) {
		this.roofed = roofed;
	}
}

//抽象的房屋建造者
public interface HouseBuilder {

	void builderBaise();
	void buildWalls();
	void buildRoofed();
	House buildHouse();
}

//具体的普通房屋建造者
public class CommonHouse implements HouseBuilder{

	private House house = new House();
	
	@Override
	public void builderBaise() {
		house.setBaise("普通房子的地基");
	}

	@Override
	public void buildWalls() {
		house.setWall("普通房子的砌墙");
	}

	@Override
	public void buildRoofed() {
		house.setRoofed("普通房子的盖屋顶");
	}

	@Override
	public House buildHouse() {
		return house;
	}
}

//具体的高楼建筑建造者
public class HighBuilding implements HouseBuilder{

	private House house = new House();
	
	@Override
	public void builderBaise() {
		house.setBaise("高楼建筑的地基");
	}

	@Override
	public void buildWalls() {
		house.setWall("高楼建筑的砌墙");
	}

	@Override
	public void buildRoofed() {
		house.setRoofed("高楼建筑的屋顶");
	}

	@Override
	public House buildHouse() {
		return house;
	}
}

//指挥者
public class HouseDirector {

	private HouseBuilder hb;
	
	public HouseDirector(HouseBuilder hb) {
		this.hb=hb;
	}
	
	//指挥者负责构建什么样的房子
	public House constructHouse() {
		hb.builderBaise();
		hb.buildWalls();
		hb.buildRoofed();
		return hb.buildHouse();
	}
}

//测试类
public class Client {
	public static void main(String[] args) {
		HouseDirector hbirector = new HouseDirector(new CommonHouse());
		House house = hbirector.constructHouse();
		System.out.println(house.getBaise());
		System.out.println(house.getWall());
		System.out.println(house.getRoofed());
	}
}

建造者模式的注意事项和细节

  1. 客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象

  2. 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象

  3. 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程

  4. 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合 “开闭原则”

  5. 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

  6. 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,因此在这种情况下,要考虑是否选择建造者模式.

在例2.5的设计中,添加一个经济型房屋生成器类,命名为EconHouseBuilder。注意经济型房屋的面积比较小,卧室、卫生间和车库的数量较少,切不包含花园和游泳池。设计并且写出实现代码,具体要求参见光盘的相应作业部分

原型模式
  1. 原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象

  2. 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节

  3. 工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即 对象.clone()

Prototype:原型类,声明一个克隆自己的接口

ConcretePrototype:具体的原型类

克隆羊案例

Sheep.java

package com.ligong.prototype;

//需要实现Cloneable接口,重写clone方法,注意将方法的异常改为try catch
public class Sheep implements Cloneable {

	private String name;
	private String color;
	private Integer age;

	public Sheep(String name, String color, Integer age) {
		super();
		this.name = name;
		this.color = color;
		this.age = age;
	}

	//get,set方法省略

	@Override
	public String toString() {
		return "Sheep [name=" + name + ", color=" + color + ", age=" + age + "]";
	}

	@Override
	protected Object clone() {
		Sheep sheep = null;
		try {
			sheep = (Sheep) super.clone();
		} catch (Exception e) {
			System.out.println(e);
		}
		return sheep;
	}

}

Client.java

package com.ligong.prototype;

public class Client {

	public static void main(String[] args) throws CloneNotSupportedException {
		Sheep sheep = new Sheep("肖恩", "yellow", 19);
		Sheep cloneSheep = (Sheep)sheep.clone();//通过clone方法直接返回克隆好的实例
		System.out.println(sheep);
		System.out.println(cloneSheep);
	}
}

(1)浅拷贝:我们只拷贝对象中的基本数据类型(8种),对于数组、容器、引用对象等都不会拷贝

(2)深拷贝:不仅能拷贝基本数据类型,还能拷贝那些数组、容器、引用对象等

深拷贝:

  • 复制对象的所有基本数据类型的成员变量值

  • 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝

  • 深拷贝实现方式1:重写clone方法来实现深拷贝

  • 深拷贝实现方式2:通过对象序列化实现深拷贝

结构型设计模式

结构型模式 : 适配器模式 , 桥接模式 , 装饰者模式 , 组合模式 , 外观模式 , 代理模式

适配器模式
  1. 适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper)

  2. 适配器模式属于结构型模式

  3. 主要分为三类:类适配器模式、对象适配器模式

类适配器

以充电头案例为例,插座的电压是220v的,而我们手机需要5v的电压,这时充电器就相当于一个适配器,将220v的电压转化成我们可以使用的5v电压

//被适配的类,透明的,用户看不见的,无法对其直接修改
public class Voltage220V {
	
	public int output220V() {
		return 220;
	}
}

//目标类,我们期望的类,将原来类中的功能保留,并添加新的功能
public interface Voltage5V {
	public int output220V();
	public int output5V();
}

//使用适配器类将原来的被适配类转换成可期望的类
public class VoltageAdapter extends Voltage220V implements Voltage5V{

	//新增了5v的接口,原来的220v也可以继续使用
	@Override
	public int output5V() {
		return 5;
	}
}


public class Client {
	public static void main(String[] args) {
		Voltage5V v5 = new VoltageAdapter();
		System.out.println("使用了" + v5.output220V() + "伏的充电接口");
		System.out.println("使用了" + v5.output5V() + "伏的充电接口");
	}
}
对象适配器

由于java是单继承,这就导致了类适配器的局限性,对象适配器使用合成复用原则替换原来的继承关系

//使用适配器类将原来的被适配类转换成可期望的类
public class VoltageAdapter2 implements Voltage5V{

	private Voltage220V v220;

        public VoltageAdapter2(Voltage220V v220) {
		this.v220 = v220;
	}
	//保留原来220v的方法
	@Override
	public int output220V() {
		return v220.output220V();
	}
	
	//实现我们期望使用的方法
	@Override
	public int output5V() {
		return 5;
	}
}

public class Client {
	public static void main(String[] args) {
		Voltage5V voltage2 = new VoltageAdapter2(new Voltage220V());
		System.out.println("使用了" + voltage2.output220V() + "伏的充电接口");
		System.out.println("使用了" + voltage2.output5V() + "伏的充电接口");
	}
}

桥接模式

桥接模式是指将抽象部分与它的实现部分分离,使它们可以独立地变化

Abstraction接口:定义抽象部分的接口,维持Implementor对象的一个参考

RefinedAbstraction类:是一个实类,继承或实现Abstraction

Implementor接口:Implementor接口的结构形式可以不和Abstraction界面严格对应;Implementor接口通常只提供比较原始的功能,Abstraction接口通常提供比较高级的功能

ConcreteImplementor类:是一个具体的实现类

组合模式

组合模式指将对象组合成树形结构,以表示“部分-整体”的层次结构。在树形结构问题中模糊了简单元素和复杂元素的概念,客户端程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦

安全形式的组合模式:在Compsite类中声明所有用来管理子类对象的方法,而不再接口中

透明形式的组合模式:在Component类中声明所有用来管理子类对象的方法

类图:

案例:

​ 文件系统中的文件有不同类型,不同类型的文件其浏览方式有所区别,如文本文件和图片文件,视频文件的浏览方式就不同。对文件夹的浏览实际上就是对其中包含文件的浏览,而客户端可以一致地对文件和文件夹进行操作,无需关心他们的区别。使用组合模式来模拟文件额浏览操作(display),画出设计类图

案例2:

​ 使用组合模式设计一个杀毒软件的框架,该软件既可以对某个文件夹杀毒,也可以对指定文件进行杀毒,也可以对某个指定的文件进行杀毒,文件种类包括文本文件TextFile、图片文件ImageFile、视频文件VideoFile。绘制类图并编程实现。

类图:

代码实现:

public abstract class AbstFile {
    String name;

    public AbstFile(String name) {
        this.name = name;
    }
    public AbstFile(){

    }
    public abstract void display();
    public abstract void add(AbstFile f);
}
//复杂元素
class Folder extends AbstFile {

    ArrayList<AbstFile> list = new ArrayList<>();

    public Folder(String name){
        super(name);
    }

    @Override
    public void display() {
        System.out.println("对***"+name+"***进行杀毒");
        for (AbstFile f : list) {
            f.display();
        }
    }

    @Override
    public void add(AbstFile f) {
        list.add(f);
    }
}
//简单元素
class ImageFile extends AbstFile {

    public ImageFile(String name){
        super(name);
    }

    @Override
    public void display() {
        System.out.println("对***"+name+"***进行杀毒");
    }

    @Override
    public void add(AbstFile f) {
        System.out.println("暂不支持该方法");
    }
}
//简单元素
class TextFile extends AbstFile {

    public TextFile(String name){
        super(name);
    }

    @Override
    public void display() {
        System.out.println("对***"+name+"***进行杀毒");
    }

    @Override
    public void add(AbstFile f) {
        System.out.println("暂不支持该方法");
    }
}
//简单元素
class VideoFile extends AbstFile {

    public VideoFile(String name){
        super(name);
    }

    @Override
    public void display() {
        System.out.println("对***"+name+"***进行杀毒");
    }

    @Override
    public void add(AbstFile f) {
        System.out.println("暂不支持该方法");
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        AbstFile folder = new Folder("我的文件夹");
        AbstFile text = new TextFile("文本文件.txt");
        AbstFile video = new VideoFile("橘生淮南.mp4");
        AbstFile image = new ImageFile("柯南.jpg");
        folder.add(text);
        folder.add(video);
        folder.add(image);
        folder.display();
    }
}

案例3:

给定如图所示的树形结构,请使用组合模式,在客户端完成数据的展示。具体要求如下:

​ 1)绘制组合模式的类图。

​ 2)编写简单元素的代码。

​ 3)编写复杂元素的代码。

​ 4)编写客户端的代码。

提示:程序运行后,输出信息应为Dir1,File1,Dir2,File3,Dir3,File4

类图:

简单元素代码:

//简单元素
public class Leaf implements Component {

    String name;

    public Leaf(String name) {
        this.name = name;
    }

    @Override
    public void display() {
        System.out.println(name);
    }

    @Override
    public void add(Component c) {
        System.out.println("暂不支持该方法");
    }

    @Override
    public void remove(Component c) {
        System.out.println("暂不支持该方法");
    }
}

复杂元素代码:

//复杂元素
public class Composite implements Component {

    String name;
    ArrayList<Component> list = new ArrayList<>();

    public Composite(String name) {
        this.name = name;
    }

    @Override
    public void add(Component c) {
        list.add(c);
    }

    @Override
    public void remove(Component c) {
        list.remove(c);
    }

    @Override
    public void display() {
        System.out.println(name);
        for (Component c : list) {
            c.display();
        }
    }
}

客户端代码:

public class Client {
    public static void main(String[] args) {
        Component root = new Composite("Dir1");
        Component comp = new Composite("Dir2");
        Component comp2 = new Composite("Dir3");
        root.add(new Leaf("File1"));
        root.add(comp);
        root.add(comp2);
        comp.add(new Leaf("File3"));
        comp2.add(new Leaf("File4"));
        root.display();
    }
}
外观模式

(应该不会考大题,不是特别重点)

装饰者模式

装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)

具体案例:

​ 请为星巴克公司的饮料销售系统编写一款收费软件。星巴克中可以提供的基础饮料有咖啡、奶茶和可乐,可以选择的配料(Condiment)有布丁(Pudding)、冰激凌(IceCream)、蓝莓(BlueBerry),客户在订购饮料时,可以在基础饮料的基础上添加任意的配料,请使用装饰者模式设计系统,要求绘制系统类图并编写代码,在测试程序中输出一杯添加了布丁和蓝莓的奶茶的价格

代码实现:

//抽象饮品类
public abstract class Drink {
    
    protected String desc;//描述
    protected int price;//价格

    public abstract int getPrice();
    public abstract String getDesc();
}
//具体的饮料类,咖啡
public class Cofe extends Drink {

    public Cofe(){
        price = 15;
        desc = "咖啡";
    }

    @Override
    public int getPrice() {
        return price;
    }

    @Override
    public String getDesc() {
        return desc;
    }
}
//可乐
public class Cola extends Drink {

    public Cola(){
        price = 17;
        desc = "可乐";
    }

    @Override
    public int getPrice() {
        return price;
    }

    @Override
    public String getDesc() {
        return desc;
    }
}
//奶茶
public class MilkTea extends Drink {

    public MilkTea() {
        price = 16;
        desc = "奶茶";
    }

    @Override
    public int getPrice() {
        return price;
    }

    @Override
    public String getDesc() {
        return desc;
    }
}
//装饰者,抽象配料类
public abstract class Condiment extends Drink{

    protected Drink drink;

    public Condiment(Drink drink){
        this.drink = drink;
    }

}
//具体的配料类,蓝莓
public class BlueBerry extends Condiment {

    public BlueBerry(Drink drink) {
        super(drink);
        desc = "蓝莓";
        price = 5;
    }

    @Override
    public int getPrice() {
        return price + drink.getPrice();
    }

    @Override
    public String getDesc() {
        return drink.getDesc() + "," + desc;
    }
}
//冰淇淋
public class IceCream extends Condiment {

    public IceCream(Drink drink) {
        super(drink);
        desc = "冰淇淋";
        price = 4;
    }

    @Override
    public int getPrice() {
        return price + drink.getPrice();
    }

    @Override
    public String getDesc() {
        return drink.getDesc() + "," + desc;
    }

}
//布丁
public class Pudding extends Condiment {

    public Pudding(Drink drink) {
        super(drink);
        desc = "布丁";
        price = 3;
    }

    @Override
    public int getPrice() {
        return price + drink.getPrice();
    }

    @Override
    public String getDesc() {
        return drink.getDesc() + "," + desc;
    }
}
//客户端使用
public class Client {
    public static void main(String[] args) {
        Drink milkTea = new MilkTea();//16
        milkTea = new Pudding(milkTea);//3
        milkTea = new BlueBerry(milkTea);//5
        System.out.println("描述:" + milkTea.getDesc() + ",价格为:" + milkTea.getPrice());//24
    }
}

行为型设计模式

行为型模式 : 命令模式 , 访问者模式 , 迭代器模式 , 观察者模式 , 责任链模式 , 状态模式 , 策略模式

策略模式

策略模式定义了一系列的算法,将每一个算法封装起来,并且使他们之间可以互相替换。策略模式让算法的变化不会影响到使用算法的客户。

类图

状态模式


案例:

设计一个台灯控制软件,台灯上有一个按键和一个旋钮,按键控制电源开关,旋钮控制台灯亮度。请用状态模式实现该控制软件的编写。

1)绘制台灯状态图

2)编写状态类与台灯类

编写测试代码,测试台灯的开关以及亮度的调节

类图:

代码实现:

//台灯类
public class Lamp {
    private LampState lampState = new CloseState(this);

    public void clickButton() {
        lampState.clickButton();
    }

    public void brightness() {
        lampState.brightness();
    }
    //动态设置台灯的状态
    public void setLampState(LampState lampState) {
        this.lampState = lampState;
    }
}

//抽象的状态类
public interface LampState {

    public void clickButton();//开关灯

    public void brightness();//调节亮度
}

//具体的状态实现类,开灯状态
class OpenState implements LampState {

    private Lamp lamp;

    public OpenState(Lamp lamp){
        this.lamp = lamp;
    }

    @Override
    public void clickButton() {
        lamp.setLampState(new CloseState(lamp));
    }

    @Override
    public void brightness() {
        System.out.println("开灯状态,变亮!!!!");
    }
}

//具体的状态实现类,关灯状态
class CloseState implements LampState {

    private Lamp lamp;

    public CloseState(Lamp lamp){
        this.lamp = lamp;
    }

    @Override
    public void clickButton() {
        lamp.setLampState(new OpenState(lamp));
    }

    @Override
    public void brightness() {
        System.out.println("关灯状态,调节无效");
    }
}

//客户端
public class Client {
    public static void main(String[] args) {
        Lamp lamp = new Lamp();//默认关灯状态
        lamp.brightness();//调节亮度无效
        lamp.clickButton();//点击按钮,变为开灯状态
        lamp.brightness();//变亮
    }
}
访问者模式

这个比较重要

迭代器模式

观察者模式

定义对象间的一种一对多的依赖关系,当一个对象的状态发生变化时,所有依赖于它的对象都得到通知并被自动更新,也叫发布-订阅模式

①主题对象管理着某些数据,一旦数据改变就会通知观察者。

②必须先订阅主题,才能成为主题的观察者。

③也可以取消订阅,就不再是观察者,不再接受通知

针对数据传递的方式,观察者的实现分为两种:

推式

Subject对象在通知观察者时,只提供一定的参数信息

拉式

Subject对象在通知观察者时,将Subject对象本身提供出去,观察者主动获取感兴趣的参数信息

具体案例:

代码实现:

//被观察者基类
public class Observable {

    //保存读者(订阅者),
    private ArrayList<Observer> observers = new ArrayList<>();

    public void register(Observer observer) {
        observers.add(observer);
    }

    public void unRegister(Observer observer) {
        observers.remove(observer);
    }

    //通知读者
    public void notifyObservers(){
        for (Observer observer : observers) {
            observer.read(this);
        }
    }
}
//被观察者的具体实现,报纸类
public class Newspaper extends Observable {

    private String name;//报纸名称
    private String info;//报纸内容

    public void setName(String name) {
        this.name = name;
    }
    //设置报纸内容
    public void setInfo(String info) {
        this.info = info;
        //新内容发布时,通知读者
        notifyObservers();
    }

    public String getName() {
        return name;
    }

    public String getInfo() {
        return info;
    }
}
//抽象观察者
public interface Observer {
    public void read(Observable observable);
}
//读者(订阅者,具体的观察者,可以有多个)
public class Reader implements Observer {

    private String username;

    public Reader(String username) {
        this.username = username;
    }

    @Override
    public void read(Observable observable) {
        System.out.println(username + "阅读了" + ((Newspaper) observable).getName()
                + ",内容是" + ((Newspaper) observable).getInfo());
    }
}
//客户端使用
public class Client {
    public static void main(String[] args) {
        Newspaper newspaper = new Newspaper();//创建一个报纸作为被观察者
        Reader r1 = new Reader("张三");//观察者1
        Reader r2 = new Reader("李四");//观察者2
        newspaper.register(r1);//将读者1注册到订阅中
        newspaper.register(r2);

        newspaper.setName("威海日报");
        newspaper.setInfo("惊!哈理工5号楼3楼有众多男生反向拉屎");//发布报纸,更新订阅

        newspaper.unRegister(r1);//将张三取消订阅

        newspaper.setName("成都日报");
        newspaper.setInfo("惊!大学里居然有很多人不会拉屎");
    }
}

设计一个机场信息系统。在该系统中有一个AirPortInfo类负责维持机场信息,例如飞机到达时间、起飞时间、延迟信息、气象信息、航班取消信息等。假设两个依赖于这些信息的类:VoiceInfo类,负责从AirportInfo类自动获取语音机场信息,然后将这些信息传送给乘客;DisplayInfo类,负责从AirportInfo类自动获取文字机场信息,然后将这些信息显示在屏幕上。请使用观察者模式设计该问题,画出类图

设计一个控制金鱼缸水质、水温与水位高度的软件系统。基本需求:该程序用于自动控制金鱼缸中的水质、水温与水位高度。系统硬件包含鱼缸、化学传感器(ChemSensor)、水温传感器(TempSensor)与水位传感器(LineSensor)。当化学传感器的读数超过某种范围时,鱼缸需要排除部分废水,同事补充新鲜的水;当水温传感器读数低于某温度,或者超过某温度值时,需要开启加热设备或者冷却设备调整水温;当水位读数高于或低于特定高度时,需要开启排水设备,排除部分水或者添加新鲜的水。使用观察者模式设计该软件系统。画出类图


使用观察者模式设计一个某路口的交通信号灯系统,系统中包含三种角色:分别是信号灯(SignalLight)、汽车(Car)和行人(Person),信号灯可以设置灯的颜色(红-黄-绿),当信号灯颜色发生变化时,汽车和行人可以按照交通规则行动(红灯停,绿灯行,遇到黄灯停一停)

(1)基于JDK对观察者模式的支持,绘制完整项目类图

(2)编写完整代码,并在客户端模拟实现汽车和行人过马路的过程

代码实现:

//具体的被观察者类,信号灯类
public class SignalLight extends Observable {

    private String lightColor;

    public void setLightColor(String color) {
        lightColor = color;
        setChanged();//设置被观察者中的changed为true
        notifyObservers(color);//通知观察者类状态发生改变
    }
}
//观察者,行人类
public class Person implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        String lightColor = (String) arg;

        if ("yellow".equals(lightColor)){
            awaiting();
        }else if ("red".equals(lightColor)){
            stop();
        }else {
            run();
        }
    }

    public void stop(){
        System.out.println("红灯,person不能通行");
    }

    public void run(){
        System.out.println("绿灯,person可以通行");
    }

    public void awaiting(){
        System.out.println("黄灯,person需要等待一会");
    }
}
//观察者,车类
public class Car implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        String lightColor = (String) arg;
        /*((SignalLight)o)*/
        if ("yellow".equals(lightColor)){
            awaiting();
        }else if ("red".equals(lightColor)){
            stop();
        }else {
            run();
        }
    }

    public void stop(){
        System.out.println("红灯,car不能通行");
    }

    public void run(){
        System.out.println("绿灯,car可以通行");
    }

    public void awaiting(){
        System.out.println("黄灯,car需要等待一会");
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        //创建被观察者实例
        SignalLight light = new SignalLight();
        //向集合中添加多个观察者
        light.addObserver(new Car());
        light.addObserver(new Person());
        //设置灯的状态
        light.setLightColor("red");
        light.setLightColor("yellow");
        light.setLightColor("green");
    }
}
责任链模式

基本类图

案例:

实现学生请假流程。 学生向老师提出请假申请,包含请假理由和请假天数。 如果天数在3天以内, 可以由老师批复, 如果天数在4天以上,10天以内可以由主任批复, 如果天数超过10天, 则要由校长批复

类图:

代码:

//学生请假条
public class Request {
    private String desc;
    private int day = 0;

    public Request(String desc, int day) {
        this.desc = desc;
        this.day = day;
    }

    public String getDesc() {
        return desc;
    }

    public int getDay() {
        return day;
    }
}
//抽象的处理者
public abstract class Handler {
    protected Handler successor;
    protected String name;

    public Handler(String name) {
        this.name = name;
    }

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public abstract void handlerRequest(Request request);
}

class Teacher extends Handler {

    public Teacher(String name) {
        super(name);
    }

    @Override
    public void handlerRequest(Request request) {
        if (request.getDay() <= 3) {
            System.out.println("请假内容为:" + request.getDesc() + "," + name + "已审批");
        } else {
            successor.handlerRequest(request);
        }
    }
}
//主任
class Director extends Handler {

    public Director(String name) {
        super(name);
    }

    @Override
    public void handlerRequest(Request request) {
        if (request.getDay() >= 4 && request.getDay() <= 10) {
            System.out.println("请假内容为:" + request.getDesc() + "," + name + "已审批");
        } else {
            successor.handlerRequest(request);
        }
    }
}

class SchoolManster extends Handler {

    public SchoolManster(String name) {
        super(name);
    }

    @Override
    public void handlerRequest(Request request) {
        if (request.getDay() > 10) {
            System.out.println("请假内容为:" + request.getDesc() + "," + name + "已审批");
        } else {
            successor.handlerRequest(request);
        }
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        Request request = new Request("家中有事", 9);

        Handler t = new Teacher("李老师");
        Handler d = new Director("秦主任");
        Handler s = new SchoolManster("孙校长");

        t.setSuccessor(d);
        d.setSuccessor(s);
        s.setSuccessor(t);

        t.handlerRequest(request);
    }
}

软件体系结构

SOA架构

绘制 SOA 架构图并描述 SOA 的工作机制,并说明 Web Service 中用什么语言来描述服务

架构图:

工作机制:

1)服务的提供者将要暴露的服务注册到公共的服务注册器中。

2)服务消费者查询服务注册器,寻找符合需求的服务。如果服务注册器中有这样的服务,它将为消费者提供该服务的描述信息(服务合同)

3)服务消费者与服务提供者将直接绑定,服务提供者开始为服务消费者执行相应的服务。

Web Service使用WSDL描述服务

绘制 MVC 体系结构逻辑示意图,并列举出软件开发中至少两个应用了 MVC思想的开发模型


本文标签: 模式软件