资料来源:up主zst_2001
第八章 设计模式
设计模式的要素
设计模式的核心在于提供了相关问题的解决方案,使得人们可以更加简单方便地复用成功的设计和体系结构。
设计模式基本要素:
- 模式名称(Pattern Name)
- 问题(Problem)
- 解决方案(Solution)
- 效果(Consequences)
创建型设计模式(5种)
Simple Factory(简单工厂)
- 简单工厂模式属创建型模式,但不属于23种设计模式之一。
- 定义:定义一个工厂类,他可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。在简单工厂模式中用于被创建实例的方法通常为静态(static)方法,因此简单工厂模式又被成为静态工厂方法
- 简单工厂模式违反了开放封闭原则,即对扩展开放对修改也开放。
/**
* 简单工厂模式
*/
public class SimpleFactory {
public static void main(String[] args) {
Product productA = Factory.createProduct("A");
productA.info();
Product productB = Factory.createProduct("B");
productB.info();
}
}
class Factory{
public static Product createProduct(String type){
Product product =null;
switch (type){
case "A":
product = new ProductA();
break;
case "B":
product = new ProductB();
break;
default:
System.out.println("没有 " + type + " 类型的产品!");
return null;
}
return product;
}
}
abstract class Product{
public abstract void info();
}
class ProductA extends Product{
@Override
public void info() {
System.out.println("产品的信息:A");
}
}
class ProductB extends Product{
@Override
public void info() {
System.out.println("产品的信息:B");
}
}
1. Factory Method(工厂方法)
1)意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。
2)结构:创建型类模式
/**
* 工厂方法模式
*/
public class FactoryMethod {
public static void main(String[] args) {
// 父类 对象名 = new 子类();
Factory factoryA = new FactoryA();
Product productA = factoryA.createProduct();
productA.info();
Factory factoryB = new FactoryB();
Product productB = factoryB.createProduct();
productB.info();
}
}
interface Factory{
Product createProduct();
}
class FactoryA implements Factory{
@Override
public Product createProduct() {
return new ProductA();
}
}
class FactoryB implements Factory{
@Override
public Product createProduct() {
return new ProductB();
}
}
interface Product{
void info();
}
class ProductA implements Product{
@Override
public void info() {
System.out.println("产品的信息:A");
}
}
class ProductB implements Product{
@Override
public void info() {
System.out.println("产品的信息:B");
}
}
3)适用性:Factory Method 模式适用于
- 当一个类不知道它所必须创建的对象的类的时候。
- 当一个类希望由它的子类来指定它所创建的对象的时候。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
2. Abstract Factory(抽象工厂)
1)意图
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
2)结构:创建型对象模式
/**
* 抽象工厂模式
*/
public class AbstractFactory {
public static void main(String[] args) {
Factory factory1 = new Factory1();
ProductA productA1 = factory1.createProductA();
productA1.info();
ProductB productB1 = factory1.createProductB();
productB1.info();
Factory factory2 = new Factory2();
ProductA productA2 = factory2.createProductA();
productA2.info();
ProductB productB2 = factory2.createProductB();
productB2.info();
}
}
// 声明一个创建抽象产品对象的操作接口
interface Factory{
ProductA createProductA();
ProductB createProductB();
}
// 实现创建具体产品对象的操作
class Factory1 implements Factory{
@Override
public ProductA createProductA() {
return new ProductA1();
}
@Override
public ProductB createProductB() {
return new ProductB1();
}
}
class Factory2 implements Factory{
@Override
public ProductA createProductA() {
return new ProductA2();
}
@Override
public ProductB createProductB() {
return new ProductB2();
}
}
// 为一类产品对象声明一个接口
interface ProductA{
void info();
}
interface ProductB{
void info();
}
// 定义一将被相应的具体工厂创建的产品对象
class ProductA1 implements ProductA{
@Override
public void info() {
System.out.println("产品的信息:A1");
}
}
class ProductA2 implements ProductA{
@Override
public void info() {
System.out.println("产品的信息:A2");
}
}
class ProductB1 implements ProductB{
@Override
public void info() {
System.out.println("产品的信息:B1");
}
}
class ProductB2 implements ProductB{
@Override
public void info() {
System.out.println("产品的信息:B2");
}
}
3)适用性:Abstract Factory 模式适用于
- 一个系统要独立于它的产品的创建、组合和表示时。
- 一个系统要由多个产品系列中的一个来配置时。
- 当要强调一系列相关的产品对象的设计以便进行联合使用时。
- 当提供一个产品类库,只想显示它们的接口而不是实现时。
3. Builder(生成器)
1)意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
2)结构:创建型对象模式
/**
* 生成器模式
*/
public class Main {
public static void main(String[] args) {
Director director = new Director();
Builder builder1 = new Builder1();
director.Construct(builder1);
Product product1 = builder1.getResult();
product1.show();
Builder builder2 = new Builder2();
director.Construct(builder2);
Product product2 = builder2.getResult();
product2.show();
}
}
class Director{
public void Construct(Builder builder){
builder.BuildPart();
}
}
abstract class Builder{
public abstract void BuildPart();
public abstract Product getResult();
}
class Builder1 extends Builder{
Product product = new Product();
@Override
public void BuildPart() {
product.add("A");
product.add("B");
product.add("C");
product.add("D");
product.add("E");
product.add("F");
}
@Override
public Product getResult() {
return product;
}
}
class Builder2 extends Builder{
Product product = new Product();
@Override
public void BuildPart() {
product.add("A");
product.add("B");
product.add("C");
}
@Override
public Product getResult() {
return product;
}
}
class Product{
List<String> parts = new ArrayList<String>();
public void add(String part){
parts.add(part);
}
public void show(){
System.out.print("产品的组成:");
for (String part : parts) {
System.out.print(part + " ");
}
System.out.println();
}
}
3)适用性:Builder 模式适用于
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
4. Prototype(原型)
1)意图
用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
2)结构:创建型对象模式
- Prototype声明一个复制自身的接口。
- ConcretePrototype 实现一个复制自身的操作。
- Client 让一个原型复制自身从而创建一个新的对象
/**
* 原型模式
*/
public class Main {
public static void main(String[] args) {
Product product1 = new Product(2022,5.28);
System.out.println(product1.getId()+ " " + product1.getPrice());
Product product2 = (Product) product1.Chlone();
System.out.println(product2.getId()+ " " + product2.getPrice());
}
}
interface Prototype{
Object Chlone();
}
class Product implements Prototype{
private int id;
private double price;
public Product(){}
public Product(int id,double price){
this.id = id;
this.price = price;
}
public int getId() {
return id;
}
public double getPrice() {
return price;
}
@Override
public Object Chlone() {
Product object = new Product();
object.id = this.id;
object.price = this.price;
return object;
}
}
3)适用性:Prototype 模式适用于
- 当一个系统应该独立于它的产品创建、构成和表示时。
- 当要实例化的类是在运行时刻指定时,例如,通过动态装载。
- 为了避免创建一个与产品类层次平行的工厂类层次时。
- 当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们,可能比每次用合适的状态手工实例化该类更方便一些。
5. Singleton(单例)
1)意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
2)结构:创建型对象模式
其中:Singleton指定一个Instance操作,允许客户访问它的唯一实例,Instance是一个类
操作:可能负责创建它自己的唯一实例。
/**
* 单例模式
*/
public class SingletonPattern {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
Singleton instance3 = Singleton.getInstance();
System.out.println("instance1: " + instance1);
System.out.println("instance2: " + instance2);
System.out.println("instance3: "+ instance3);
}
}
class Singleton{
private static Singleton instance = new Singleton();
private Singleton(){};
public static Singleton getInstance(){
return instance;
}
}
3)适用性 Singleton 模式适用于:
- 当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
- 当这个唯一实例应该是通过子类化可扩展的,并且客户无须更改代码就能使用一个扩展的实例时。
结构型设计模式(7种)
1. Adapter(适配器)
1)意图
将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
2)结构
其中:
- Target定义Client使用的与特定领域相关的接口。
- Client与符合Target接口的对象协同。
- Adaptee定义一个已经存在的接口,这个接口需要适配。
- Adapter对Adaptee的接口与Target接口进行适配。
/**
* 适配器模式
*/
public class AdapterPattern {
public static void main(String[] args) {
Target target = new Adapter();
target.Request();
}
}
class Target{
public void Request(){
System.out.println("普通请求~");
}
}
/**
* 适配器
*/
class Adapter extends Target {
private Adaptee adaptee = new Adaptee();
@Override
public void Request() {
adaptee.SpecificRequest();
}
}
class Adaptee{
public void SpecificRequest(){
System.out.println("特殊请求~");
}
}
3)适用性
Adapter 模式适用于:
- 想使用一个已经存在的类,而它的接口不符合要求。
- 想创建一个可以服用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。(了解)
- (仅适用于对象Adapter)想使用一个已经存在的子类,但是不可能对每一个都进行子 类化以匹配它们的接口。对象适配器可以适配它的父类接口。(了解)
2. Bridge(桥接)
1)意图
将抽象部分与其实现部分分离,使它们都可以独立地变化。
2)结构
/**
* 桥接模式
*/
public class BridgePattern {
public static void main(String[] args) {
Product productA = new ProductA();
Product productB = new ProductA();
Color red = new Red();
productA.setName("产品A");
productA.setColor(red);
productA.Operation();
Blue blue = new Blue();
productB.setName("产品B");
productB.setColor(blue);
productB.Operation();
}
}
abstract class Product{
private String name;
protected Color color;
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setColor(Color color){
this.color = color;
}
public abstract void Operation();
}
interface Color{
void OperationImpl(String name);
}
class ProductA extends Product{
@Override
public void Operation() {
color.OperationImpl(this.getName());
}
}
class Red implements Color{
@Override
public void OperationImpl(String name) {
System.out.println(name + ": 红色" );
}
}
class Blue implements Color{
@Override
public void OperationImpl(String name) {
System.out.println(name + ": 蓝色" );
}
}
3)适用性(了解)
- 不希望在抽象和它的实现部分之间有一个固定的绑定关系。
- 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。
- 对一个抽象的实现部分的修改应对客户不产生影响,即客户代码不必重新编译。(C++)想对客户完全隐藏抽象的实现部分。
- 有许多类要生成的类层次结构。
- 想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。
3. Composite(组合)
1)意图
将对象组合成树型结构以表示“部分-整体”的层次结构。Composite 使得用户对单个对象 和组合对象的使用具有一致性。
2)结构
其中:
- Component 为组合中的对像声明接口:在适当情况下实现所有类共有接口的默认行为:声明一个接口用于访问和管理 Component 的子组件;(可选)在递归结构中定义一个接口,用于访问一个父组件,并在合适的情况下实现它。
- Leaf 在组合中表示叶结点对象,叶结点没有子结点;在组合中定义图元对象的行为。
- Composite定义有子组件的那些组件的行为;存储子组件;在Component接口中实现与子组件有关的操作。
- Client 通过 Component 接口操纵组合组件的对象。
import java.util.*;
/**
* 组合模式
*/
public class CompositePattern {
public static void main(String[] args) {
// 父类名 对象名 = new 子类名();
AbstractFile root = new Folder("root");
AbstractFile folderA = new Folder("folderA");
AbstractFile folderB = new Folder("folderB");
AbstractFile fileC = new File("fileC");
AbstractFile fileD = new File("fileD");
AbstractFile fileE = new File("fileE");
root.Add(folderA);
root.Add(folderB);
root.Add(fileC);
folderA.Add(fileD);
folderA.Add(fileE);
print(root);
}
static void print(AbstractFile file){
file.printName();
List<AbstractFile> childrenList = file.getChildren();
if (childrenList == null){
return;
}
for (AbstractFile children : childrenList) {
print(children);
}
}
}
abstract class AbstractFile{
protected String name;
public void printName(){
System.out.println(name);
}
public abstract boolean Add(AbstractFile file);
public abstract boolean Remove(AbstractFile file);
public abstract List<AbstractFile> getChildren();
}
class Folder extends AbstractFile {
private List<AbstractFile> childrenList = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
@Override
public boolean Add(AbstractFile file) {
return childrenList.add(file);
}
@Override
public boolean Remove(AbstractFile file) {
return childrenList.remove(file);
}
@Override
public List<AbstractFile> getChildren() {
return childrenList;
}
}
class File extends AbstractFile{
public File(String name) {
this.name = name;
}
@Override
public boolean Add(AbstractFile filei) {
return false;
}
@Override
public boolean Remove(AbstractFile file) {
return false;
}
@Override
public List<AbstractFile> getChildren() {
return null;
}
}
3)适用性
Composite 模式下适用于:
- 想表示对象的部分-整体层次结构。
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
4. Decorator(装饰器)
1)意图
动态地给一个对象添加一些额外的职责。就增加功能而言,Decorator模式比生成子类更加灵活。
2)结构
其中:
- Component定义一个对象接口,可以给这些对象动态地添加职责。
- ConcreteComponent定义一个对象,可以给这个对象添加一些职责。
- Decorator 维持一个指向 Component 对象的指针,并定义一个与Component 接口一致的接口。
- ConcreteDecorator 向组件添加职责。
/**
* 装饰器模式
*/
public class DecoratorPattern {
public static void main(String[] args) {
Person zhangsan = new Student("张三");
zhangsan = new DecoratorA(zhangsan);
zhangsan = new DecoratorB(zhangsan);
zhangsan.Operation();
System.out.println("==========分割线==============");
// 对像链
Person lisi = new DecoratorB(new DecoratorA(new Student("李四")));
lisi.Operation();
}
}
abstract class Decorator extends Person{
protected Person person;
}
class DecoratorA extends Decorator{
public DecoratorA(Person person){
this.person = person;
}
@Override
public void Operation() { // 职责
person.Operation(); // 原本的职责
System.out.println("写作业~");
}
}
class DecoratorB extends Decorator{
public DecoratorB(Person person){
this.person = person;
}
@Override
public void Operation() { // 职责
person.Operation(); // 原本的职责
System.out.println("考试~");
}
}
abstract class Person{
protected String name;
public abstract void Operation(); // 职责
}
class Student extends Person{
public Student(String name){
this.name = name;
}
@Override
public void Operation() {
System.out.println(name + "的职责:学习~");
}
}
3)适用性
Decorator 模式适用于:
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 处理那些可以撤销的职责。
- 当不能采用生成子类的方式进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是,由于类定义被隐藏,或类定义不能用于生成子类。(了解)
5. Facade(外观)
1)意图
为子系统中的一组接口提供一个一致的界面,Facade 模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
2)结构
其中:
- Facade知道哪些子系统类负责处理请求;将客户的请求代理给适当的子系统对象。
- Subsystem classes实现子系统的功能;处理有Facade对象指派的任务;没有Facade的任何相关信息,即没有指向Facade的指针。
import java.util.Scanner;
/**
*/
public class FacadePattern {
public static void main(String[] args) {
Facade facade = new Facade();
facade.methodA();
facade.methodB();
facade.methodC();
}
}
class Facade{
SubSystemOne subSystemOne;
SubSystemTwo subSystemTwo;
SubSystemThree subSystemThree;
public Facade(){
subSystemOne = new SubSystemOne();
subSystemTwo = new SubSystemTwo();
subSystemThree = new SubSystemThree();
}
public void methodA(){
subSystemOne.methodOne();
}
public void methodB(){
subSystemTwo.methodTwo();
}
public void methodC(){
subSystemThree.methodThree();
}
}
class SubSystemOne{
public void methodOne(){
System.out.println("执行子系统一的功能~");
}
}
class SubSystemTwo{
public void methodTwo(){
System.out.println("执行子系统二的功能~");
}
}
class SubSystemThree{
public void methodThree(){
System.out.println("执行子系统三的功能~");
}
}
3)适用性
Facade 模式适用于:
- 要为一个复杂子系统提供一个简单接口时。
- 客户程序与抽象类的实现部分之间存在着很大的依赖性。
- 当需要构建一个层次结构的子系统时,使用 Facade 模式定义子系统中每层的入口点。
6. Flyweight(享元)
1)意图
运用共享技术有效地支持大量细粒度的对象。
2)结构
其中:
- Flyweight 描述一个接口,通过这个接口 Flyweight 可以接受并作用于外部状态。
- ConcreteFlyweight 实现Flyweight接口,并为内部状态(如果有)增加存储空间。
- ConcreteFlyweight 对象必须是可共享的。它所存储的状态必须是内部的,即它必须独立于 ConcreteFlyweight 对象的场景。
- 并非所有的 Flyweight 子类都需要被共享。Flyweight 接口使共享成为可能,但它并不强制共享。在 Flyweight 对象结构的某些层次,UnsharedConcreteFlyweight 对象通常将ConcreteFlyweight 对象作为子结点。
- FlyweightFactory 创建并管理Flyweight对象;确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory 对象提供一个已创建的实例或者在不存在时创建个实例。
- Client 维持一个对 Flyweight 的引用;计算或存储一个或多个 Flyweight 的外部状态。
/**
* 享元模式 案例1
*/
public class FlyweightPattern {
public static void main(String[] args) {
PieceFactory factory = new PieceFactory();
Piece whitePiece1 = factory.getPiece(0);
whitePiece1.draw(66,87);
System.out.println(whitePiece1);
Piece blackPiece1 = factory.getPiece(1);
blackPiece1.draw(20,11);
System.out.println(blackPiece1);
Piece whitePiece2 = factory.getPiece(0);
whitePiece1.draw(26, 54);
System.out.println(whitePiece2);
Piece blackPiece2 = factory.getPiece(1);
blackPiece2.draw(12, 34);
System.out.println(blackPiece2);
}
}
class PieceFactory{
private Piece[] pieces = {new WhitePiece(),new BlackPiece()};
public Piece getPiece(int key){
if (key == 0) return pieces[0];
else return pieces[1];
}
}
abstract class Piece{
protected String color;
public abstract void draw(int x,int y);
}
class WhitePiece extends Piece{
public WhitePiece(){
this.color = "white";
}
@Override
public void draw(int x, int y) {
System.out.println("draw a color: "+color + " piece x: " + x + " y: " + y);
}
}
class BlackPiece extends Piece{
public BlackPiece(){
this.color = "black";
}
@Override
public void draw(int x, int y) {
System.out.println("draw a color: " + color + " piece x: " + x + " y: " + y);
}
}
/**
* 享元模式 案例2
*/
public class FlyweightPattern {
public static void main(String[] args) {
ShapeFactory factory = new ShapeFactory();
Random random = new Random();
String[] colors = {"red","blue","green","whilte","black"};
for (int i = 1; i <= 10; i++) {
int x = random.nextInt(colors.length);
Shape shape = factory.getShape(colors[x]);
System.out.print("第" + i + "个圆:");
shape.draw(random.nextInt(2022),random.nextInt(528));
}
}
}
class ShapeFactory{
private Map<String,Shape> map = new HashMap<>();
public Shape getShape(String key){
if (!map.containsKey(key)) {
map.put(key, new Circle(key));
System.out.println("create color: " + key + " circle");
}
return map.get(key);
}
}
abstract class Shape {
protected String color;
public abstract void draw(int x, int y);
}
class Circle extends Shape {
public Circle(String color){
this.color = color;
}
@Override
public void draw(int x, int y) {
System.out.println("draw a color: " + color + " circle x:"+ x + " y:" + y);
}
}
3)适用性
Flyweight模式适用于:
- 一个应用程序使用了大量的对象。
- 完全由于使用大量的对象,造成很大的存储开销。
- 对象的大多数状态都可变为外部状态。
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
- 应用程序不依赖于对象标识。由于Flyweight对象可以被共享,所以对于概念上明显有别的对象,标识测试将返回真值。
7. Proxy(代理)
1)意图
为其他对象提供一种代理以控制对这个对象的访问。
2)结构
/**
* 代理模式
*/
public class ProxyPattern {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Proxy proxy = new Proxy(realSubject);
proxy.buy();
}
}
interface Subject{
void buy();
}
class Proxy implements Subject{
protected RealSubject realSubject;
public Proxy(RealSubject realSubject){
this.realSubject = realSubject;
}
@Override
public void buy() {
System.out.println("办理购买前的手续~");
realSubject.buy(); // 付钱
System.out.println("办理购买后的手续~");
}
}
class RealSubject implements Subject{
@Override
public void buy() {
System.out.println("付钱~");
}
}
3)适用性 (了解) Poxy模式适用于在需要比较通用和复杂的对象指针代替简单的指针的时候,常见情况有:
- 远程代理(Remote Proxy)为一个对象在不同地址空间提供局部代表。
- 虚代理(Virtual Proxy)根据需要创建开销很大的对象。
- 保护代理(Protection Proxy)控制对原始对象的访问,用于对象应该有不同的访问权限的时候。
- 智能引用(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。
行为设计模式(11种)
1. Chain of Responsibility(责任链)
1)意图
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
2)结构
其中:
- Handler定义一个处理请求的接口;(可选)实现后继链。
- ConcreteHandler处理它所负责的请求;可访问它的后继者;如果可处理该请求,就处理它,否则将该请求转发给后继者。
- Client向链上的具体处理者(ConcreteHandler)对象提交请求。
/**
* 责任链模式
*/
public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
Handler counsellor = new Counsellor();
Handler dean = new Dean();
Handler headmaster= new Headmaster();
counsellor.setNext(dean);
dean.setNext(headmaster);
counsellor.HandRequest(25);
}
}
abstract class Handler{
protected Handler next;
public void setNext(Handler next){
this.next =next;
}
public abstract void HandRequest(int request);
}
class Counsellor extends Handler{
@Override
public void HandRequest(int request) {
if (request <= 7){
System.out.println("辅导员审批通过~");
}else {
if (next != null){
next.HandRequest(request);
}else {
System.out.println("无法审批");
}
}
}
}
class Dean extends Handler{
@Override
public void HandRequest(int request) {
if (request <= 15){
System.out.println("院长审批通过~");
}else {
if (next != null){
next.HandRequest(request);
}else {
System.out.println("无法审批");
}
}
}
}
class Headmaster extends Handler{
@Override
public void HandRequest(int request) {
if (request <= 30){
System.out.println("校长审批通过~");
}else {
if (next != null){
next.HandRequest(request);
}else {
System.out.println("无法审批");
}
}
}
}
3)适用性
Chain of Responsibility 模式适用于以下条件:
- 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
- 想在不明确指定接收者的情况下向多个对象中的一个提交一个请求。
- 可处理一个请求的对象集合应被动态指定。
2. Command(命令)
1)意图
将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
2)结构
其中:
- Command声明执行操作的接口。
- ConcreteCommand 将一个接收者对象绑定于一个动作:调用接收者相应的操作,以实现Execute。
- Client 创建一个具体命令对象并设定它的接收者。
- Invoker 要求该命令执行这个请求。
- Receiver 知道如何实施与执行一个请求相关的操作。任何类都可能作为一个接收者。
/**
* 命令模式
*/
public class CommandPattern {
public static void main(String[] args) {
Tv tv = new Tv(); // 接收者 对象 电视机
Command onCommand = new OnCommand(tv); // 命令对象 开机命令
Command offCommand = new OnCommand(tv); // 命令对象 关机命令
Invoker invoker = new Invoker(); //请求者
invoker.setCommand(onCommand); // 给请求者设置 开机 命令
invoker.call(); // 请求者去请求命令
System.out.println("==============分割线===============");
invoker.setCommand(offCommand); // 给请求者设置 关机命令
invoker.call(); // 请求者去请求命令
}
}
class Invoker{ // 请求者
private Command command; // 命令
public void setCommand(Command command){ // 设置请求者的命令
this.command = command;
}
public void call(){ // 调用
command.Execute();
}
}
interface Command{ // 命令接口
void Execute(); // 执行命令
}
class OnCommand implements Command{// 开机命令
private Tv tv;
public OnCommand(Tv tv){
this.tv = tv;
}
@Override
public void Execute() {
tv.OnAction();
}
}
class OffCommand implements Command{ // 关机命令
private Tv tv;
public OffCommand(Tv tv){
this.tv = tv;
}
@Override
public void Execute() {
tv.OffAction();
}
}
class Tv{
public void OnAction(){ // 开机行为
System.out.println("电视机开机了...");
}
public void OffAction(){ // 关机行为
System.out.println("电视机关机了...");
}
}
3)适用性
Command 模式适用于:
- 抽象出待执行的动作以参数化某对象。
- 在不同的时刻指定、排列和执行请求。
- 支持取消操作。
- 支持修改日志。
- 用构建在原语操作上的高层操作构造一个系统。
3. Interpreter(解释器)
1)意图
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来 解释语言中的句子。
2)结构
/**
* 解释器模式
*/
public class InterpreterPattern {
public static void main(String[] args) {
Context context = new Context();
context.check("A区的开发人员");
context.check("B区的调试人员");
context.check("C区的测试人员");
System.out.println("========分割线=============");
context.check("D区的程序员");
context.check("D区的测试员");
context.check("C区的程序员");
}
}
class Context{
private String[] regions = {"A区","B区","C区"};
private String[] persions = {"开发人员","测试人员","调试人员"};
private NonterminalExpression nonterminal;
public Context(){
TerminalExpression region = new TerminalExpression(regions);
TerminalExpression person = new TerminalExpression(persions);
nonterminal = new NonterminalExpression(region,person);
}
public void check(String info){
boolean result = nonterminal.Interpret(info);
if (result){
System.out.println("识别成功~");
}else {
System.out.println("识别失败~");
}
}
}
interface Expression{
boolean Interpret(String info);
}
class NonterminalExpression implements Expression{
private TerminalExpression region;
private TerminalExpression person;
public NonterminalExpression(TerminalExpression region,TerminalExpression person){
this.region =region;
this.person = person;
}
@Override
public boolean Interpret(String info) {
String[] str = info.split("的");
// B区鹅调试人员 --> str = {"B区","调试人员"};
return region.Interpret(str[0]) && person.Interpret(str[1]);
}
}
class TerminalExpression implements Expression{
private Set<String> set = new HashSet<>();
public TerminalExpression(String[] data){
for (String str : data) {
set.add(str);
}
}
@Override
public boolean Interpret(String info) {
return set.contains(info);
}
}
3)适用性
Interpreter模式适用于当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时,以下情况效果最好:
- 该文法简单。对于复杂的发文,文法的类层次变得庞大而无法管理。
- 效率不是一个关键问题。最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种形式。
4. Iterator(迭代器)
1)意图
提供一种方法顺序访问一个聚合对象中的各个元素,且不需要暴露该对象的内部表示。
2)结构
其中:
- Iterator (迭代器)定义访问和遍历元素的接口。
- ConcreteIterator(具体迭代器)实现迭代器接口;对该聚合遍历时跟踪当前位置。
- Aggregate( 聚合)定义创建相应迭代器对象的接口。
- ConcreteAggregate (具体聚合)实现创建相应迭代器的接口,该操作返回 ConcreteIterator的一个适当的实例。
/**
* 迭代器模式
*/
public class IteratorPattern {
public static void main(String[] args) {
BookAggregate bookAggregate = new BookAggregate();
String[] books = {"数据结构","操作系统","计算机网络","计算机组成原理"};
double[] prices = {10.24,20.48,40.96,81.92};
for (int i = 0; i < 4; i++) {
bookAggregate.Add(new Book(books[i],prices[i]));
}
Iterator iterator = bookAggregate.CreateIterator();
while (iterator.hasNext()) {
Book book = (Book) iterator.next();
System.out.println("书名:" + book.getName() + " 价格:" + book.getPrice());
}
}
}
interface Iterator{
boolean hasNext();
Object next();
}
class BookIterator implements Iterator{
private int index;
private BookAggregate bookAggregate;
public BookIterator(BookAggregate bookAggregate){
this.index = 0;
this.bookAggregate = bookAggregate;
}
@Override
public boolean hasNext() {
if (index < bookAggregate.getSize()){
return true;
}
return false;
}
@Override
public Object next() {
Object obj = bookAggregate.get(index);
index ++ ;
return obj;
}
}
class BookAggregate implements Aggregate{
private List<Book> list = new ArrayList<>();
public void Add(Book book){
list.add(book);
}
public Book get(int index){
return list.get(index);
}
public int getSize(){
return list.size();
}
@Override
public Iterator CreateIterator() {
return new BookIterator(this);
}
}
interface Aggregate{
Iterator CreateIterator();
}
class Book{
private String name;
private double price;
public Book(String name,double price){
this.name = name;
this.price = price;
}
public String getName(){
return name;
}
public double getPrice(){
return price;
}
}
3)适用性
Iterator 模式适用于:
- 访问一个聚合对象的内容而无须暴露它的内部表示。
- 支持对聚合对象的多种遍历。
- 为遍历不同的聚合结构提供一个统一的接口。
5. Mediator(中介者)
1)意图
用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
2)结构
其中:
- Mediator (中介者)定义一个接口用于各同事(Colleague)对象通信。
- ConcreteMediator (具体中介者)通过协调各同事对象实现协作行为;了解并维护它的各个同事。
- Colleague class (同事类)知道它的中介者对象;每一个同事类对象在需要与其他同事通信的时候与它的中介者通信。
/**
* 中介者模式
*/
public class MediatorPattern {
public static void main(String[] args) {
ConcreteMediator mediator = new ConcreteMediator();
Colleague1 colleague1 =new Colleague1(mediator);
Colleague2 colleague2 = new Colleague2(mediator);
mediator.setColleague1(colleague1);
mediator.setColleague2(colleague2);
colleague1.sendMessage("软考加油~");
colleague2.sendMessage("祝你上岸~");
}
}
abstract class Colleague{
protected Mediator mediator;
}
class Colleague1 extends Colleague{
public Colleague1(Mediator mediator){
this.mediator = mediator;
}
public void sendMessage(String message){
mediator.sendMessage(message,this);
}
public void Notify(String message){
System.out.println("同事1收到消息:" + message);
}
}
class Colleague2 extends Colleague{
public Colleague2(Mediator mediator){
this.mediator = mediator;
}
public void sendMessage(String message){
mediator.sendMessage(message,this);
}
public void Notify(String message){
System.out.println("同事2收到消息:" + message);
}
}
abstract class Mediator{
public abstract void sendMessage(String message,Colleague colleague);
}
class ConcreteMediator extends Mediator{
private Colleague1 colleague1;
private Colleague2 colleague2;
public void setColleague1(Colleague1 colleague1){
this.colleague1 = colleague1;
}
public void setColleague2(Colleague2 colleague2){
this.colleague2 = colleague2;
}
@Override
public void sendMessage(String message, Colleague colleague) {
if (colleague == colleague1){
// 让同事2收到消息
colleague2.Notify(message);
}else {
// 让同事1收到消息
colleague1.Notify(message);
}
}
}
3)适用性
Mediator 模式适用于:
- 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。
- 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
- 想定制一个分布在多个类中的行为,而又不想生成太多的子类。
6. Memento(备忘录)
1)意图
在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。
2)结构
/**
* 备忘录模式
*/
public class MementoPattern {
public static void main(String[] args) {
Caretaker caretaker = new Caretaker();
Originator originator = new Originator();
originator.setState("1024");
Memento backup1 = originator.createMemento();
caretaker.addMemento(backup1);
originator.setState("2048");
Memento backup2 = originator.createMemento();
caretaker.addMemento(backup2);
originator.setState("4096");
Memento backup3 = originator.createMemento();
caretaker.addMemento(backup3);
System.out.println(originator.getState());
caretaker.showMemento();
Memento memento1 = caretaker.getMemento(2);
originator.setState(memento1.getState());
System.out.println("根据第2次备份还原之后的状态为:" + originator.getState());
}
}
class Originator{ // 原发器
private String state;
public void setState(String state){
this.state = state;
}
public String getState(){
return state;
}
public Memento createMemento(){
return new Memento(state);
}
public void setMemento(Memento memento){
state = memento.getState();
}
}
class Memento{ // 备忘录
private String state;
public String getState(){
return state;
}
public Memento(String state){
this.state = state;
}
}
class Caretaker{ // 管理者
private List<Memento> mementoList = new ArrayList<>();
public void addMemento(Memento memento){
mementoList.add(memento);
}
public Memento getMemento(int index){
// 判断参数是否合法
if (index >=1 && index <= mementoList.size()) {
return mementoList.get(index - 1);
}
return null;
}
public void showMemento(){
int cnt = 1;
for (Memento memento : mementoList) {
System.out.println("第" + cnt + "次备份,状态为:" + memento.getState());
cnt ++;
}
}
}
3)适用性
Mement 模式适用于:
- 必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
- 如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
7. Observer(观察者)
1)意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2)结构
其中:
- Subject(目标)知道它的观察者,可以有任意多个观察者观察同一个目标;提供注册和删除观察者对象的接口。
- Observer(观察者)为那些在目标发生改变时需获得通知的对象定义一个更新接口。
- ConcreteSubject(具体目标)将有关状态存入各ConcreteObserver对象;当它的状态发生改变时,向它的各个观察者发出通知。
- ConcreteObserver (具体观察者)维护一个指向 ConcreteSubject 对象的引用;存储有关状态,这些状态应与目标的状态保持一致
- 实现 Observer 的更新接口,以使自身状态与目标的状态保持一致。
/**
* 观察者模式
*/
public class ObserverPattern {
public static void main(String[] args) {
Subject subjectA = new ConcreteSubject("目标A");
Observer observerB = new ConcreteObserver("张三",subjectA);
Observer observerC = new ConcreteObserver("李四",subjectA);
Observer observerD = new ConcreteObserver("王五",subjectA);
subjectA.setState("更新了");
}
}
interface Subject { // 目标接口
void Attach(Observer observer); // 添加观察者
void Detach(Observer observer); // 删除观察者
void Notify(); // 状态改变后,通知所有观察者
void setState(String state); // 设置状态(改变状态)
String getState(); // 获取状态
}
class ConcreteSubject implements Subject {
private String name;
private String state;
private List<Observer> observerList;
public ConcreteSubject(String name) {
state = "未更新";
this.name = name;
observerList = new ArrayList<>();
}
@Override
public void Attach(Observer observer) {
observerList.add(observer);
}
@Override
public void Detach(Observer observer) {
observerList.remove(observer);
}
@Override
public void Notify() {
for (Observer observer : observerList) {
observer.update();
}
}
@Override
public void setState(String state) {
this.state = state;
System.out.println(name + "的状态发生变化,变化后的状态为:" + state);
Notify();
}
@Override
public String getState() {
return state;
}
}
interface Observer { // 观察者接口
void update(); // 收到通知,更新观察者的状态
}
class ConcreteObserver implements Observer {
private String name;
private String state;
private Subject subject;
public ConcreteObserver(String name, Subject subject) {
this.name = name;
this.subject = subject;
subject.Attach(this);
state = subject.getState();
}
@Override
public void update() {
System.out.println(name + " 收到通知");
state = subject.getState(); // 让当前观察者的状态 和 目标改变后的状态保持一致
System.out.println(name + " 改变后的状态为:"+state);
}
}
3)适用性
Observer 模式适用于:
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变时。
- 当一个对象必须通知其他对象,而它又不能假定其他对象是谁,即不希望这些对象是紧耦合的。
8. State(状态)
1)意图
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
2)结构
/**
* 状态模式
*/
public class StatePattern {
public static void main(String[] args) {
Context context = new Context(); // count = 3
System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());
context.Request(); // 购买一个饮料 count = 2
context.Request(); // 购买一个饮料 count = 1
context.Request(); // 购买一个饮料 count = 0
System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());
context.Request(); // 无货,等待补货
System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());
context.Request(); // 购买一个饮料 count = 4
System.out.println("状态:" + context.getState() + " 数量:" + context.getCount());
}
}
class Context{ // 贩卖机
private int count;
private State state;
public Context(){
count = 3;
state = new StateA();
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void Request(){ // 购买饮料
state.Handle(this);
}
}
interface State{
void Handle(Context context);
}
class StateA implements State{
@Override
public void Handle(Context context) {
int count = context.getCount();
if (count >= 1){
System.out.println("购买成功~");
context.setCount(count - 1);
if (context.getCount() == 0){
context.setState(new StateB()); // 设置为无货状态
}
}else {
System.out.println("购买失败~");
}
}
}
class StateB implements State{
@Override
public void Handle(Context context) {
int count = context.getCount();
if (count == 0){
System.out.println("购买失败!等待补货~");
context.setCount(5);
System.out.println("补货成功,请重新购买~");
context.setState(new StateA());
}
}
}
3)适用性
State 模式适用于:
- 一个对象的行为决定于它的状态,并且它必须在运行时刻根据状态改变它的行为。
- 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态常用一个或多个枚举常量表示。
9. Strategy(策略)
1)意图
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。此模式使得算法可以独立于使用它们的客户而变化。
2)结构
/**
* 策略模式
*/
public class StrategyPattern {
public static void main(String[] args) {
OperationContext context = new OperationContext(new Addstrategy());
context.Operation(20,17);
context = new OperationContext(new Substrategy());
context.Operation(20,17);
context = new OperationContext(new Multstrategy());
context.Operation(20,17);
}
}
class OperationContext{
private Strategy strategy;
public OperationContext(Strategy strategy){
this.strategy =strategy;
}
public void Operation(int a, int b){
strategy.TwoNumberOperation(a,b);
}
}
interface Strategy{
void TwoNumberOperation(int a,int b);
}
class Addstrategy implements Strategy{
@Override
public void TwoNumberOperation(int a, int b) {
System.out.println(a + b);
}
}
class Substrategy implements Strategy{
@Override
public void TwoNumberOperation(int a, int b) {
System.out.println(a - b);
}
}
class Multstrategy implements Strategy{
@Override
public void TwoNumberOperation(int a, int b) {
System.out.println(a * b);
}
}
3)适用性
Strategy 模式适用于:
- 许多相关的类仅仅是行为有异。
- 需要使用一个算法的不同变体。
- 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
- 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,将相关的条件分支移入它们各自的 Strategy 类中,以代替这些条 件语句。
10. Template Method(模板方法)
1)意图
定义一个操作中的算法骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
2)结构
其中:
- AbstractClass(抽象类)定义抽象的原语操作,具体的子类将重定义它们以实现一个算法的各步骤;实现模板方法,定一个算法的骨架,该模板方法不仅调用原语操作,也调用定义在 AbstractClass 或其他对象中的操作。
- ConcreteClass(具体类)实现原语操作以完成算法中与特定子类相关的步骤。
/**
* 模板方法模式
*/
public class TemplateMethodPattern {
public static void main(String[] args) {
// 父类名 对象名 = new 子类名();
Person student = new Student();
Person teacher = new Teacher();
student.TemplateMethod();
System.out.println("=========分割线=============");
teacher.TemplateMethod();
}
}
abstract class Person{
public void TemplateMethod(){
System.out.println("上课 去教室");
PrimitiveOperation1();
System.out.println("下课 离开教室");
PrimitiveOperation2();
}
public abstract void PrimitiveOperation1(); // 原语操作 1:上课过程 学生 听课... 老师 讲课
public abstract void PrimitiveOperation2(); // 原语操作 2:作业 学生 写作业 提交作业... 老师批改作业 打分数
}
class Student extends Person{
@Override
public void PrimitiveOperation1() {
System.out.println("学生:听课 学习 做笔记 提出问题");
}
@Override
public void PrimitiveOperation2() {
System.out.println("学生:写作业 提交作业");
}
}
class Teacher extends Person{
@Override
public void PrimitiveOperation1() {
System.out.println("老师:上课 讲课 解答问题 布置作业");
}
@Override
public void PrimitiveOperation2() {
System.out.println("老师:批改作业 打分数");
}
}
3)适用性
Template Method 模式适用于:
- 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
- 各子类中公共的行为应被提取出来并集中到一个公共父类中,以避免代码重复。
- 控制子类扩展:模板方法在特定点调用“hook”操作(默认行为,子类可以在必要时进行重定义扩展),这就只允许在这些点进行扩展。
11. Visitor(访问者)
1)意图
表示一个作用于某对象结构中的各元素的操作。它允许在不改变各元素的类的前提下定义作用于这些元素的新操作。
2)结构
其中:
- Visitor(访问者)为该对象结构中 ConcreteElement 的每一个类声明一个 Visit 操作。该操作的名字和特征标识了发送 Vist 请求给该访问者的那个类,这使得访问者可以确定正被访问元素的具体的类。这样访问者就可以通过该元素的特定接口直接访问它。
- ConcreteVisitor (具体访问者)实现每个有 Visitor 声明的操作,每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。Concrete Visitor为该算法提供了上下文并存储它的局部状态。这一状态常常在遍历该结构的过程中累积结果。
- Element (元素)定义以一个访问者为参数的 Accept 操作。
- ConcreteElement (具体元素)实现以一个访问者为参数的 Accept 操作。
- ObjectStructure (对象结构)能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个组合或者一个集合,如一个列表或一个无序集合。
/**
* 访问者模式
*/
public class VisitorPattern {
public static void main(String[] args) {
PersonStructure structure = new PersonStructure();
Visitor1 visitor1 = new Visitor1();
System.out.println("访问者1的访问记录:");
structure.Accept(visitor1);
System.out.println("学生年龄的总和:" + visitor1.getStudentAgeSum() +" 老师年龄的总和:" + visitor1.getTeacherAgeSUm());
System.out.println("=========分割线==============");
Visitor2 visitor2 = new Visitor2();
System.out.println("访问者2的访问记录:");
structure.Accept(visitor2);
System.out.println("学生的最高成绩:" + visitor2.getMaxScore() + " 老师的最高工龄:" + visitor2.getMaxWorkYear());
}
}
interface Visitor{
void VistStudent(Student student); // 访问
void vistTeacher(Teacher teacher); // 访问老师
}
class Visitor1 implements Visitor{ // 访问者1 分别统计学生和老师的年龄总和
private int studentAgeSum = 0;
private int teacherAgeSUm =0;
public int getStudentAgeSum() {
return studentAgeSum;
}
public int getTeacherAgeSUm() {
return teacherAgeSUm;
}
@Override
public void VistStudent(Student student) {
System.out.println("访问者1访问学生:" + student.getName() + " 年龄:" + student.getAge());
studentAgeSum += student.getAge();
}
@Override
public void vistTeacher(Teacher teacher) {
System.out.println("访问者1访问老师:" + teacher.getName() + " 年龄:" + teacher.getAge());
teacherAgeSUm += teacher.getAge();
}
}
class Visitor2 implements Visitor{ // 访问者2 分别求出 学生的最高成绩 以及 老师的最高工龄
private int maxScore = -1;
private int maxWorkYear = -1;
public int getMaxScore() {
return maxScore;
}
public int getMaxWorkYear() {
return maxWorkYear;
}
@Override
public void VistStudent(Student student) {
System.out.println("访问者2访问学生:" + student.getName() + " 成绩:" + student.getScore());
maxScore = Math.max(maxScore,student.getScore());
}
@Override
public void vistTeacher(Teacher teacher) {
System.out.println("访问者2访问老师:" + teacher.getName() + " 工龄:" + teacher.getWorkYear());
maxWorkYear = Math.max(maxWorkYear,teacher.getWorkYear());
}
}
class PersonStructure{
private List<Person> personList = new ArrayList<>();
public PersonStructure(){
personList.add(new Student("张三",20,70));
personList.add(new Student("李四",21,80));
personList.add(new Student("王五",22,90));
personList.add(new Teacher("李老师",26,3));
personList.add(new Teacher("陈老师",27,4));
personList.add(new Teacher("刘老师",28,5));
}
public void Accept(Visitor visitor){
for (Person person : personList) {
person.Accept(visitor);
}
}
}
abstract class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge() {
return age;
}
public abstract void Accept(Visitor visitor);
}
class Student extends Person{
private int score;
public Student(String name,int age,int score){
super(name,age);
this.score = score;
}
public int getScore(){
return score;
}
@Override
public void Accept(Visitor visitor) {
visitor.VistStudent(this);
}
}
class Teacher extends Person{
private int workYear;
public Teacher(String name,int age,int workYear){
super(name,age);
this.workYear = workYear;
}
public int getWorkYear(){
return workYear;
}
@Override
public void Accept(Visitor visitor) {
visitor.vistTeacher(this);
}
}
3)适用性
Visitor 模式适用于:
- 一个对象结构包含很多类对象,它们有不同的接口,而用户想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而又想要避免这些操作“污染”这些对象的类。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
第九章 算法设计与分析
时间复杂度
算法时间复杂度以算法中基本操作重复执行的次数(简称为频度)作为算法的时间度量。一般不必要精确计算出算法的时间复杂度,只要大致计算出相应的数量级即可,如O(1)、O(㏒₂n)、O(n)或O(n²)等。
递归式时间复杂度:递归的次数 x 每次递归的时间复杂度
主方法。主方法也称为主定理,给出了求解以下形式的递归式的快速方法。
空间复杂度
非递归:O(1) O(n) O(n²)
回溯法
n皇后问题
#include<stdio.h>
#include"stdlib.h"
int Place(int *Column,int index){
int i;
for(i=1;i<index;i++){
int Column_differ = abs(Column[index] - Column[i]);
int Row_differ = abs(index - i);
if(Column[i] == Column[index] || Column_differ == Row_differ)
return 0;
}
return 1;
}
void N_Queue(int n){
int Column_Num[n+1];
int index = 1;
int i;
int answer_num = 0;
for(i=1;i<=n;i++)
Column_Num[i] = 0;
while(index>0){
Column_Num[index]++;
while(Column_Num[index] <= n && !Place(Column_Num,index))
Column_Num[index]++;
if(Column_Num[index] <=n){
if (index == n) {
answer_num++;
printf("方案%d:",answer_num);
for(i=1;i<= n;i++){
printf("%d ",Column_Num[i]);
}
printf("\n");
}else {
index++;
Column_Num[index]=0;
}
}else {
index--;
}
}
}
int main(){
N_Queue(6);
return 0;
}
分治法
递归有两个基本要素:
- 边界条件,即确定递归到何时终止,也称为递归出口
- 递归模式,即大问题是如何分解为小问题的,也称为递归体
分支算法在每一层递归上都有 3 个步骤:
- 分解。将原问题分解成一系列子问题。
- 求解。递归地求解各子问题。若子问题足够小,则直接求解。
- 合并。将子问题的解合并成原问题的解。
归并排序算法
#include<stdio.h>
#define INT_MAX 2147483647
/**
* 归并排序
**/
void Merge(int A[],int p,int q,int r){
int n1 = q - p + 1,n2 = r -q,i,j,k;
int L[50],R[50];
for(i=0;i<n1;i++)
L[i] = A[p+i];
for(j=0;j<n2;j++)
R[j] = A[q+j+1];
L[n1] = INT_MAX;
R[n2] = INT_MAX;
i=0;
j=0;
for(k=p;k<r+1;k++){
if(L[i] < R[j]){
A[k] = L[i];
i++;
}else{
A[k]=R[j];
j++;
}
}
}
void MergeSort(int A[],int p,int r){
int q;
if(p < r){
q = (p+r) / 2;
MergeSort(A, p, q);
MergeSort(A, q+1, r);
Merge(A, p, q,r);
}
}
int main(){
int A[] = {4,1,3,6,7,5,2,9};
MergeSort(A, 0, 7);
int i;
for (i = 0; i<8; i++) {
printf("%d ",A[i]);
}
printf("\n");
return 0;
}
最大字段和问题
#include<stdio.h>
#include<stdlib.h>
int MaxSubSum(int * Array,int left,int right){
int sum = 0;
int i;
if(left == right){ /*分解到单个整数,不可继续分解*/
if(Array[left] > 0)
sum = Array[left];
else
sum = 0;
}else{
/*从 left 和 right 的中间分解数组*/
int center = (left + right)/2; /*划分的位置*/
int leftsum = MaxSubSum(Array, left, center);
int rightsum = MaxSubSum(Array, center+1, right);
/*计算包括 center 的最大值,判断是情形1、情形2还是情形3*/
int s1 = 0;
int lefts = 0;
for(i = center;i >= left;i--){
lefts = lefts + Array[i];
if(lefts > s1)
s1 = lefts;
}
int s2 = 0;
int rights = 0;
for(i = center + 1;i<= right;i++){
rights = rights + Array[i];
if(rights > s2)
s2 = rights;
}
sum = s1 + s2;
/*情形1*/
if (sum < leftsum) {
sum = leftsum;
}
/*情形2*/
if(sum < rightsum){
sum = rightsum;
}
}
return sum;
}
int main(){
int *Array = (int *)malloc(6*sizeof(int));
Array[0] = -2;
Array[1] = 11;
Array[2] = -4;
Array[3] = 13;
Array[4] = -5;
Array[5] = -2;
int result = MaxSubSum(Array, 0, 5);
printf("%d\n",result);
return 0;
}
动态规划法
0-1 背包问题
#include<stdio.h>
#define N 4 // 物品数量
#define W 5 // 背包容量
int max(int a,int b){
return a > b ? a : b;
}
int main(){
int v[] = {0,2,4,5,6}; // 物品价值数组
int w[] = {0,1,2,3,4}; // 物品重量数组
int f[N + 1][W + 1] = {}; // 子问题解数组
int i,j;
for(i=1;i<=N;i++){
for(j=1;j<=W;j++){
if(j >= w[i]){ // 选第 i 个物品的前提条件
// 等于不选第 i 个物品 和 选第 i 个物品 两者的较大值
f[i][j] = max(f[i-1][j],f[i-1][j-w[i]] + v[i]);
}else{ // 不选第 i 个物品
f[i][j] = f[i - 1][j]; // 等于从前 i-1 个物品中选,背包容量为 j 时的最大价值
}
}
}
printf("%d\n",f[N][W]);
return 0;
}
时间复杂度:O(N*W) N:物品数量 W:背包容量
矩阵连乘问题
- 时间复杂度:O(n³)
- 空间复杂度O(n²)
贪心法
部分背包问题
#include<stdio.h>
#define N 5 // 物品数量
#define W 100 // 背包容量
// 显示物品价值、重量、单位重量价值数组
void show(int v[],int w[],double vw[]){
int i;
printf("物品价值数组:");
for(i = 1;i<=N;i++) printf("%d ",v[i]);
printf("\n");
printf("物品重量数组:");
for(i = 1;i<=N;i++) printf("%d ",w[i]);
printf("\n");
printf("物品单位重量价值数组:");
for(i = 1;i<=N;i++) printf("%0.1lf ",vw[i]);
printf("\n");
}
double Max_Value(int v[],int w[],double vw[]){
double result = 0.0;
int i;
int w_temp = W;
for(i=1;i<=N;i++){
if(w_temp >= w[i]){
result = result + v[i];
w_temp = w_temp - w[i];
}else{
break;
}
}
if(w_temp > 0 && i<=N){
result = result + w_temp * vw[i];
}
return result;
}
int main(){
int v[] = {0,65,20,30,60,40}; // 物品价值数组
int w[] = {0,30,10,20,50,40}; // 物品重量数组
double vw[N + 1]; // 物品单位重量价值数组
int i;
// 初始化 物品单位重量价值数组
for(i = 1;i<=N;i++) vw[i] = (double) v[i] / w[i];
show(v, w, vw);
double result =Max_Value(v, w, vw);
printf("\nreslut %.1lf\n",result);
return 0;
}
第十章 数据库
概念数据模型(E-R图)
-
实体:客观存在并且可以相互区别的事物称为实体。如一个单位,一个职工
-
属性:描述实体的特征称为属性。如学生实体用若干属性(学号、姓名、性别、出生日期、班级号)来描述。
-
码:唯一标识实体的属性称为码。如学号是学生实体的码。
-
域:属性的取值范围称为该属性的域。如性别域为(男、女)
-
联系:实体之间的对应的关系称为联系。
-
实体内部个属性之间的联系
-
实体之间的联系
-
一对一联系(1:1)。如班和班长之间是一对一联系。
-
一对多联系(1:n)。班和学生之间是一对多联系。
-
多对多联系(m:n)。课程和学生之间是多对多联系。
-
-
三级模式结构
- 外模式 ——> 视图
- 概念模式(模式) ——> 基本表
- 内模式 ——> 存储文件
两级映像
数据库系统在三级模式之间提供了两级映像:模式/内模式映像、外模式/模式映像。 保证了数据库中的数据具有较高的逻辑独立性和物理独立性。
- 模式/内模式映像:实现了概念模式和内模式之间的相互转换。
- 外模式/模式映像:实现了外模式和概念模式之间的相互转换。
- 数据的物理独立性:需要修改概念模式和内模式之间的映像。
- 数据的逻辑独立性:需要修改外模式和概念模式之间的映像。
关系型模式的基本术语
- 关系:一个关系就是一张二维表,每个关系有一个关系名
- 元组:表中的一行即为一个元组,对应存储文件中的一个记录值。
- 属性:表中的列称为属性,每一列有一个属性名。属性值相当于记录中的数据项或者字段值。
- 域:属性的取值范围。
- 关系模式:对关系的描述称为关系模式,由关系名和其属性集合构成,关系模式的格式为:关系名(属性名1,属性名2,…,属性名n)
- 候选码(候选健):属性或属性组合其值能够唯一地标识一个元组。
- 主码(主键):在一个关系中可能有多个候选码,从中选择一个作为主码。
- 主属性:所有候选键都称为主属性,其他的属性都称为非主属性。
- 外码(或外键):如果一个关系中的属性或属性组并非该关系(二维表)的码,但它们是另外一个关系(二维表)的码,则称其为该关系的外码。
- 全码:关系模式的所有属性组是这个关系模式的候选码,称为全码。
- 超码(超键):一个包含码的属性集称为超码。例如学号是码,则(学号,姓名)就是一个超码。
完整性约束
完整性规则保证用户对数据库做修改时不会破坏数据的一致性。
- 实体完整性:关系中主码的值不能为空或部分为空。即主属性不能为空。
- 参照完整性:如果关系R2的外码X与关系R1的主码相对应,则外码X的每个值必须在关系R1中的主码中找到,或者为空值。
- 用户定义完整性:指用户对某一具体数据指定的约束条件进行检验。(如手机号码为11位)
关系代数运算符
-
投影:投影运算是从关系的垂直方向进行运算,在关系R中选出若干属性列A组成新的关系,记作πA(R)
-
选择:选择运算是从关系的水平方向进行运算,是从关系R中选择满足给定条件的的元组,记作σF(R)
-
连接:连接运算是从两个关系R和S的笛卡儿积中选取满足条件的元组。
-
θ连接:从R与S的笛卡儿积中选取属性间满足一定条件的元组。
-
等值连接:当 θ 为 “=” 时,称之为等值连接。
-
自然连接:自然连接是一种特殊的等值连接,它要求两个关系中进行比较的分量必须是相同的属性组,并且在结果集中将重复属性列去掉。
可以认为笛卡儿积是无条件连接,其他的连接操作认为是有条件连接。
-
-
外连接:外连接运算是连接运算的扩展,可以处理由于连接运算而缺失的信息。(p27集)
- 左外连接(⟕):取出左侧关系中所有与右侧关系中任一元组都不匹配的元组,用空值null充填所有来自右侧关系的属性,构成新的元组,将其加入自然连接的结果中。
- 右外连接(⟖):取出右侧关系中所有与左侧关系中任一元组都不匹配的元组,用空值null填充所有来自左侧关系的属性,构成新的元组,将其加入自然连接的结果中。
- 全外连接(⟗)。完成左外连接和右外连接的操作。即填充左侧关系中所有与右侧关系中任一元组都不匹配的元组,并填充右侧关系中所有与左侧关系中任一元组都不匹配的元组,将产生的新元组加入自然连接的结果中。
SQL语言
-
SQL不支持列的序号
-
投影、选择转SQL语言
-
笛卡尔积转SQL语言
- 自然连接转SQL语言
SQL语言的分类
-
DDL(Data Definition Language,数据定义语言):用来定义数据库对象:数据库,表,列等。
关键字:
CREATE、DROP、ALTER等。 -
DML(Data Manipulation Language,数据操作语言):用来对数据库中表的数据进行增删改。
关键字:
INSERT、DELETE、UPDATE等。 -
DQL(Data Query Language,数据查询语言):用来查询数据库中表的记录。
关键字:
SELECT等。 -
DCL(Data Control Language,数据控制语言):用来定义数据库的访问权限和安全级别,及创建用户。
SQL控制语句
- 插入权限:insert on
- 允许将该权限授予他人:WITH GRANT OPTION
- 视图:WITH CHECK IPTION
关系模式的范式
候选码中包含的属性称为主属性、不包含在候选码中的属性称为非主属性。若候选码多于一个,可以选定其中的一个为主码。
范式之间的关系
1NF(第一范式)
定义:若关系模式 R 每一个分量是不可再分的数据项,则关系模式 R 属于第一范式。
1NF可能存在的问题:
- 数据冗余:数据的冗余度大,R中可能出现多个元组在多个属性集中值相同
- 修改异常:引起修改操作的不一致性,修改一条记录可能需要修改其他多条记录才能保持数据一致性(由数据冗余引起)
- 插入异常:主码不能取空值或部分空值,会出现插入异常
- 删除异常:本该删除但又客观存在的元组,会出现删除异常。即,删除掉的数据可能包含着其他本不该被删除的属性
问题的原因是1NF中可能存在部分函数依赖。
2NF(第二范式)
定义:若关系模式 R∈1NF,且每一个非主属性完全依赖于码,则关系模式 R∈2NF。
当 1NF 消除了非主属性对码的部分函数依赖,则称为 2NF。
可能存在数据冗余和更新异常等问题。
3NF(第三范式)
2NF 消除了非主属性对码的传递函数依赖,则称为 3NF。
属于 3NF 的关系模式 R 可能存在主属性对候选码的部分依赖和传递依赖。
BC范式(BCNF)
定义:R是一个关系模式,F是它的依赖集,R属于BCNF,当且仅当其F中的每个依赖的决定因素必定包含R的某个候选码。
BC范式已经消除了插入和删除异常
规范化步骤
NF到4NF之间的转换关系:
| 范式 | 转换关系 |
|---|---|
| 1NF | 每一个分量是不可再分的数据项 |
| 2NF | 1NF消除了部分函数依赖后满足2NF |
| 3NF | 2NF消除了非主属性对候选码的传递函数依赖后满足3NF |
| BCNF | 3NF消除了主属性对候选码的部分和传递函数依赖后满足BCNF |
| 4NF | BCNF消除非平凡且非函数依赖的多值依赖后满足4NF |
数据库设计
新奥尔良法是目前公认的数据库设计方法,它将数据库设计分为以下几个阶段:
- 用户需求分析:收集用户需求,确定系统边界
- 概念结构设计:E—R图
- 逻辑结构设计:E—R图转换成关系模式、规范化
- 物理结构设计
需求分析
- 需求分析是后面几个阶段,逻辑结构设计、物理结构设计以及应用程序设计的依据。
- 需求分析将收集到的零碎的、局部的数据分析整理后,建立需求说明文档、数据字典和数据流程图。
- 需求分析阶段的成果:系统需求说明书、数据流图、数据字典、需求说明文档、各种说明性白表格
概念结构设计
对需求分析阶段所得到的数据进行分类、聚集和概括,确定实体、属性和联系。
- 选择局部应用
- 逐一设计分 E-R 图
- E-R 图合并
E-R 图之间的冲突
- 属性冲突。同一属性可能会存在于不同的分 E-R 图。
- 命名冲突。异名同义、同名异议
- 结构冲突。同一实体在不同的分E—R图中有不同的属性,同一对象在某一个E—R图中被抽象为实体,而在另一个E—R图中被抽象为属性,需要统一。
逻辑结构设计
逻辑结构设计阶段的主要工作步骤包括:
- 确定数据模型
- 将 E-R 图转换成为指定的数据模型
- 确定完整性约束和确定用户视图
- 关系规范化
事物管理
事务是一个操作序列,这些操作“要么都做,要么都不做”。
事务和程序是两个不同的概念,一般一个程序可包含多个事务。
事务的ACID性质:
- 原子性:事务是原子的,要么都做,要么都不做。
- 一致性:事务执行的结果必须保证数据库从一个一致性状态变到另一个一致性状态。
- 隔离性:事务相互隔离。当多个事务并发执行时,任一事务的更新操作直到其成功提交的整个过程,对其他事务都是不可见的。
- 持久性:一旦事务成功提交,即使数据库崩溃,其对数据库的更新操作也将永久有效。
分布式数据库
- 分片透明:指用户或应用程序不需要知道逻辑上访问的表具体是怎么分块存储的
- 复制透明:指采用复制技术的分布方法,用户不需要知道数据是复制到哪些节点,如何复制的。
- 位置透明:指用户无须知道数据存放的物理位置
- 逻辑透明:指用户或应用程序无需知道局部场地使用的是哪种数据模型
- 共享性:指数据存储在不同的结点数据共享
- 自治性:指每结点对本地数据都能独立管理
- 可用性:指当某一场地故障时,系统可以使用其他场地上的副本而不至于使整个系统瘫痪
- 分布性:指数据在不同场地上的存储
第十一章 计算机网络
网络的设备
- 物理层:中继器、集线器(可以看作成一种特殊的多路或多端口的中继器)
- 数据链路层:网桥、交换机(可以看成多端口的网桥)
- 网络层:路由器、ICMP(控制报文协议)
- 应用层:网关
| 广播域 | 冲突域 | |
|---|---|---|
| 物理层(集线器) | × | × |
| 数据链路层(交换机) | × | √ |
| 网络层(路由器) | √ | √ |
协议簇
- FTP的端口号:20(数据端口)、21(控制端口)
- http的端口号:80
- https的端口号:443
- DNSD的端口号:53
TCP和UDP
-
TCP(传输控制协议):在IP提供的不可靠数据服务的基础上为应用程序提供了可靠的、面向连接的、全双工的数据传输服务。采用三次握手来确认建立和关闭连接是否成功。TCP的功能或服务有:
- 可靠传输
- 连接管理
- 差错校验和重传
- 流量控制:采用可变大小的滑动窗口协议
- 拥塞控制
- 端口寻址
-
UDP(用户数据报协议):是一种不可靠的、无连接的协议,可以保证应用程序进程间的通信。UDP上的应用有VoIP等。
- UDP的首部8B,TCP的首部20B,UDP相比TCP来说,开销较小。
- TCP和UDP均提供了端口寻址功能。
补充:
- TCP和UDP都是应用于传输层的网络协议。
- TCP有助于提供可靠性,UDP有助于提高传输的高速率性。
电子邮件协议 SMTP 和 POP3
- SMTP和POP3都使用TCP端口传输和接收邮件。
- SMTP:仅传输 ASCII 文本,不能传输非文字性附件。主要用来发邮件,可以使用MIME(邮件附件k扩展协议),添加其他类型的附件。TCP端口号:25。
- POP3:邮件接收协议;TCP端口号:110。
- POP3基于C/S模式(Client/Server模式,客户端/服务器模式)。
- PEM:私密邮件
ARP和RARP
-
地址解析协议(ARP)和反地址解析协议(RARP)是网络层的一个重要的协议
-
ARP(地址解析协议):将IP地址转换为MAC地址(物理地址)。
IP到MAC地址的转换过程:
- 查询ARP高速缓存中是否有该IP地址
- 如果该IP地址在ARP高速缓存中,便使用与它对应的MAC地址,将数据报发送给所需的物理网卡
- 如果ARP高速缓存中没有该IP地址,ARP便在局域网上以广播方式发送一个ARP请求包
- 如果局域网上IP地址与某台计算机中的IP地址相一致,那么该计算机便生成一个ARP应答信息(单播),信息中包含对应的MAC地址。(广播传送请求,单播传送响应)
-
RARP(反地址解析协议):将MAC地址转换为IP地址,主要用于无盘工作站。
DHCP(动态主机配置协议)
-
DHCP协议的功能和作用是:
- 集中的管理、自动分配IP地址
- 使网络环境中的主机动态地获得IP地址、Gateway地址、DNS服务器地址等信息
- 提升地址的使用率
DHCP客户端可以从DHCP服务器获得以下内容:
- 本机IP地址
- DNS服务器地址
- DHCP服务器地址
- 默认网关的地址
无效地址:
-
Windows无效地址:169.254.X.X
169.254.X.X是Windows系统在DHCP信息租用失败时自动给客户机分配的IP地址
-
Linux无效地址:0.0.0.0
URL
协议名://主机名.域名.域名后缀.域名分类/目录/网页文件
| 组织模式 | 含义 | 地理模式 | 含义 |
|---|---|---|---|
| com | 商业机构 | cn | 中国 |
| edu | 教育机构 | hk | 中国香港 |
| gov | 政府机构 | mo | 中国澳门 |
| mil | 军事部门 | tw | 中国台湾 |
| net | 主要网络支持中心 | us | 美国 |
| org | 上述以外组织 | uk | 英国 |
| int | 国际组织 | jp | 日本 |
IPv6 128位地址空间、IPv4 32位地址空间。
浏览器
- DNS域名查询次序是:本地的hosts文件——本地DNS缓存——本地DNS服务器——根域名服务器
- 主域名服务器在接受域名请求后查询顺序是:本地缓存——本地hosts文件——本地数据库——转发域名服务器
internet地址
Internet地址格式主要有两种书写形式:
- 域名
- IP地址
IP地址
IP地址:Internet中的主机地址实际上是用IP地址来唯一标识的。
IP地址有两种:
- IPv4
- IPv6
通常IP地址是指IPv4。
IPv4
每个IPv4地址都由4个小于256的数字组成(每个数字8位,共32位),数字之间用.分开,可分为5类:
补充:
- 在IPv4中,全
0代表的是网络,全1代表的是广播。 - IPv4能表示的地址个数为:2^32^≈40亿。
子网掩码
网络软件和路由器使用子网掩码来识别报文是仅存放在网络内部还是被路由转发到其他地方。
子网掩码是用来指明特定的IP地址中的网络号和主机号部分。子网掩码的格式与IP地址相同:
- 所有对应网络号的部分用
1填上; - 所有对应主机号的部分用
0填上。
IPv6
IPv6具有长达128位的地址空间,可以彻底解决IPv4地址不足的问题。
IPv6理论上能表示的地址个数:2^128^=3.4×10^38^
在想象得到的将来,IPv6的地址空间是不可能用完的。
无线通信技术
流行的无线通信技术有WiFi、蓝牙等。其中,蓝牙覆盖范围最小、通信距离最短。
ipconfig 命令
- ipconfig用于查询本机IP信息。
- traceroute:是Linux下的命令,对应windows命令为tracert路由跟踪命令
- netstat:是一个监控TCP/IP网络的非常有用的工具。它可以显示路由表、实际的网络连接以及每一个网络接口设备的状态信息
- nslookup:域名查询命令,用于查询DNS解析域名记录
ipconfig命令的用法如下:
| 参数 | 说明 | 示例 |
|---|---|---|
| 无参数 | 显示所有网络适配器的IP地址、子网掩码和缺省网关值 | ipconfig |
/all | 显示所有网络适配器的完整TCP/IP配置信息,包括DHCP服务是否已启动 | ipconfig /all |
/displaydns | 显示本地DNS内容 | ipconfig /displaydns |
/flushdns | 清除本地DNS缓存内容 | ipconfig /flushdns |
/registerdns | DNS客户端手工向服务器进行注册 | ipconfig /registerdns |
/release | DHCP客户端手工释放IP地址/释放所有连接 | ipconfig /release |
/renew | DHCP客户端手工向服务器刷新请求(重新申请IP地址)/更新所有适配器 | ipconfig /renew |
信息安全
防火墙技术
防火墙是建立在内外网络边界上的过滤封锁机制。
补充内容
- 防火墙工作层次越低,工作效率越高,安全性越低
- DMZ的作用是保存一些公共服务器(Web服务器、Eamil服务器)
- 防火墙的安全性从高到底:内网-------DMZ--------外网
- 防火墙不能提供漏洞扫描,查毒等功能
-
包过滤防火墙
- 过滤型的防火墙通常是直接转发报文,它对用户完全透明,速度较快。对网络层的数据报文进行检查。处在网络层(TCP)和数据链路层(IP)
- 优点:防火墙对每条传出网络的包实行低水平控制。每个IP字段都被检查,如:源地址、目标地址、协议和端口号
- 缺点:不能防范黑客攻击、不支持应用层协议、不能处理新的安全威胁。
-
应用代理网关防火墙
- 内网用户对外网的访问变成防火墙对外网的访问,然后再由防火墙转发给内网用户。处在应用层、传输层和网络层。
- 优点:检查应用层、传输层和网络层的协议特征对数据包的检测能力比较强
- 缺点:难以配置、处理速度非常慢(网络整体性能低)
-
状态检测技术防火墙
- 状态检测技术防火墙结合了代理防火墙的安全性和包过滤防火墙的高速度等优点。在不损失安全性的基础上,提高了代理防火墙的性能
病毒
计算机病毒可以分为:
- 文件型计算机病毒:可以感染可执行文件(exe和com文件)
- 引导型计算机病毒:影响软盘或硬盘的引导扇区
- 宏病毒:感染的对象是使用某些程序创建的文本文档(docx)、数据库、电子表格等文件,
- 目录型计算机病毒:可以修改硬盘上储存的所有文件的地址
计算机病毒的特征包括:传播性、破坏性、隐蔽性、感染性、潜伏性、触发性等。
worm表示蠕虫病毒、Trojan表示特洛伊木马(秘密潜伏且能够通过远程网络进行控制的恶意程序)、Backdoor表示后门病毒、Macro表示宏病毒
- 木马软件: 冰河、X卧底
- 蠕虫病毒: 欢乐时光、熊猫烧香、红色代码、爱虫病毒、震网
补充病毒与木马的区别
【病毒】:
- 破坏者——人为的,可自我复制的
- 具有:潜伏性、传染性、隐蔽性、破坏性、多样性、条件触发性
【木马】:
- 盗窃者
- 不产生图标、伪装成“系统服务”的方式、自动运行、具备自动恢复、能自动开启端口,建立网络连接
网络攻击
- 主动攻击:拒绝服务攻击(Dos)、分布式拒绝服务(DDos)、认证处理、信息篡改、资源使用、欺骗、伪装、重放等
- 被动攻击:嗅探、信息收集等
- 拒绝服务攻击 (Dos攻击) : 目的是使计算机或网络无法提供正常的服务(拒绝服务攻击是不断向计算机发起请求来实现的)。
- 重放攻击: 攻击者发送一个目的主机已经接受过的报文来达到攻击目的。攻击者利用网络监听或者其他方式盗取认证凭据,之后再重新发送给认证服务器。主要用于身份认证过程,目的是破坏认证的正确性。
- 口令入侵攻击:使用某些合法用户的账号和口令登录到目的主机,然后再实施攻击活动。
- 特洛伊木马:被伪装成程序或游戏,当用户下载了带有木马的软件或附件时,这个程序就会向黑客发起连接请求,建立连接后黑客就实施攻击活动。
- 端口欺骗攻击: 采用端口扫描找到系统漏洞从而实施攻击。
- 网络监听: 攻击者可以接收某一网段在同一条物理通道上传输的所有信息使用网络监听可以轻松截取包括账号和口令在内的信息资料。
- IP欺骗攻击: 产生的IP数据包为伪造的源IP地址,以便冒充其他系统或发件人的身份。(ARP)
- sql注入攻击: 是黑客对数据库进行攻击的常用手段之一。没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。攻击者可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据首先获取数据库的权限,就可获取用户账号和口令信息,以及对某些数据修改等。
- 入侵检测(用户的非授权访问)技术: 专家系统、模型检测、简单匹配。
网络安全
- SSL是传输层安全协议安全加密,用于实现web的安全通信,端口号443。
- TLS是IETF制定的协议,是SSL的后续版本
- 安全连接的协议是SSH,也是传输层基础上的安全协议,SSH终端设备与远程站点之间建立安全连接
- HTTPS是使用SSL加密算法的HTTP
- MIME多用途互联网电子邮件附件扩展类型。扩展了电子邮件的标准,使其能够支持更多的文本
- PGP是一个基于RSA公钥加密体系的邮件加密软件
- IPSes为IP数据报文进行加密
- RFB远程登录图形化界面,IGMP因特网组管理器
- 内部网关协议:RIP、OSPF 外部网关协议:BGP
安全需求
- 物理线路安全:机房安全
- 网络安全:入侵检测
- 系统安全:漏洞补丁
- 应用安全:数据库安全
第十二章 知识产权
著作权(也称为版权):是指作者对其创作的作品享有的人身权和财产权。
人身权包括:
- 发表权(时限是作者终身及其死亡后50年)
- 署名权(不受时间限制)
- 修改权(不受时间限制)
- 保护作品完整权(不受时间限制)
财产权(受时间限制)包括:
- 作品的使用权
- 获得报酬
职务作品开发人员(软件设计师)只享有署名权(不能被继承)
应用技术
试题一
题目形式:文字说明 + 两张数据流图 + 问题
数据流图(DFD)
数据流图的基本图形元素包括数据流、加工、数据存储和外部实体。
-
外部实体(实体只能是唯一的) :当前系统之外的人、物、外部系统
- 人:学生、老师、员工、主管、医生、客户、供应商......
- 物:传感器、控制器、单车、车辆、采购部门......
- 外部系统:支付系统、车辆交易系统、库存管理系统、道闸控制系统......
-
数据存储:存储数据和提供数据,存储加工的输出数据和提供加工的输入数据
-
例子:客户表、订单表、学生表
-
巴士列表文件、维修记录文件、课表文件
- 加工:将输入数据处理后得到输出数据
- 一个加工至少有一个输入数据流和一个输出数据流
- 加工只有输入没有输出称为:黑洞
- 加工只有输出没有输入称为:白洞
- 加工的输入数据不足以产生输出数据:灰洞
- 数据流的起点或终点必须至少有一个是加工
问题一(易)
找实体名称
写法: E1 :病人 E2:护理人员 E3:医生
问题二(易)
找数据存储名称
写法:D1:XX 表 XX 文件
D1:销售订单表 D2:库存表 D3:生产计划表 D 4:配方表 D5:采购订单表
问题三(15~20分钟)
题型:
- 根据说明和图中术语,补充图1-2中缺失的数据流及其起点和终点(三条即可)。
- 图1-2中缺失了4条数据流,使用说明、图1-1和图1-2中的术语,给出数据流的名称及其起点和终点。
- 根据说明和图中词语,补充图1-2中缺失的数据流及其起点和终点。
三个解题方法
- 父图子图平衡
- 加工既有输入数据流也有输出数据流
- 数据守恒
注意事项:数据流的起点和终点必须有一个是加工
答题格式:
-
如何保持数据流图平衡?
- 父图中加工的输入数据流必须与子图中的输入输出数据流在数量上和名字上相同;
- 父图中的一个输入(输出)数据流对应子图中几个输入(输出)数据流,而子图中组成这些数据流的数据项全体正好是父图中的这一条数据流。
试题二
数据库设计:
-
需求分析
-
概念模型 问题1 :E-R图
-
逻辑结构 问题2:关系模式
-
题型结构
- 说明
- 需求分析
- 概念模型(E-R图)
- 逻辑结构
- 问题
实体
实体用矩形表示,通常矩形框内写明实体名。
- 弱实体:使用双线矩形框表示。将需要依赖其他实体存在的实体。即一个实体的存在必须以另一个实体为前提。
例如职工与家属的联系,家属总是属于某职工的(在关系模式中需要依赖职工而存在),所以家属是弱实体。
- 子实体:又称为子类,它会有一个超类,并且能继承超类的属性,超类的属性是实体集中所有子实体的相同属性。
-
超类和子类的转化
超类、子类实体都可以转换为一个关系,并将超类实体的主码加到子类实体中
联系
联系用菱形表示,通常菱形框内写明联系名。 1:1:
- 转关系模式
- 归并到任一方实体
1:*:
- 转关系模式,关系的码是多方实体的码
- 归并到多方实体,把一方实体主键加到多方实体的关系模式属性,归并后多方实体的码保持不变
*:*:只能转化成一个独立的关系模式,关系的码是多方实体的码构成的属性组
属性
用椭圆形表示,并用无向边将其与相应的实体连接起来
- 简单属性和复合属性。简单属性是原子的、不可再分的复合属性可以细分为更小的部分(即划分为别的属性)。
- 单值属性和多值属性。单独的一个值。
- 派生属性。派生属性可以从其他属性得来。
试题三
UML 的关系
- 依赖
-
关联:是一种结构关系,描述了一个组链,链是对象之间的连接
- 聚合:部分和整体的生命周期不一样,整体消失了,部分仍存在,部分可以脱离整体存在。
- 组合 :部分和整体的生命周期一样,整体消失了,部分也消失,部分不可以脱离整体存在。
-
泛化(继承) :父类泛化子类
-
实现:类实现一个接口
UML 的图
-
UML 类图
- 类
- 依赖、泛化、关联关系、实现(少见)
- 接口(不考)
- 协作(不考)
-
UML 用例图
-
用例。
-
参与者。
-
用例之间的扩展关系(<>)和包含关系(<>),参与者和用例之间的关联关系,用例与用例以及参与者与参与者之间的泛化关系。
-
试题四
N皇后问题
-
按行来摆放皇后
-
判断同一列
列列
-
判断同一条斜线:
行行列列