OOP设计模式

常用的设计模式以及UML类图

UML类图

Java考试的内容实在太多了,今天先把各种了之间的关系复习一下。

在所有的连线中,没有特殊图形的一端均表示线的开始,起始端是没有任何图形的。

依赖关系

  • UML中表示方法:用一条带箭头的虚线连接两个类的UML图,其中结束端即箭头指向被依赖的类
  • 定义: 如果一个类作为另一个类某个方法的返回值类型或者参数类型,那么这两个类就构成了依赖关系。

例如: 台式电脑需要连接电源🔌供电(指电能而非机箱内的电源)才能启动,电源供电并不是台式电脑的属性(成员),而是作为电脑💻启动这个方法不可或缺的条件。电脑和电能就构成了依赖关系。

Code of Computer:

1
2
3
4
5
6
7
class Computer{
boolean Switch;

boolean Boot(EPower e){
return (e.state==true)&&Switch?true:false;
}
}

Code of EPower:

1
2
3
class EPower{
boolean state;
}

依赖关系

关联关系

记忆:依赖关系和关联关系都是结束端的箭头都是相同的,而关联是实线, 的同音为实线,并且实线较虚线有关系更强的意思。

  • 在UML类图中: 用带箭头的实线连接两个相互关联的类,其中箭头表示的结束段指向被关联的类
  • 定义: 如果一个类声明的对象作为另一个类的数据成员(属性、成员变量),那么这两个类之间就形成了关联关系。

例如: CPU(中央处理器)作为计算机不可缺少的一部分,CPU就是计算机的属性。

Code of Cpu:

1
2
3
class Cpu{
String structure;
}

Code of Computer:

1
2
3
4
5
6
class Computer{
Cpu intel = new Cpu();
boolean boot(){
return true;
}
}

关联

泛化(继承)关系

  • UML类图中,用一条实线加空心的三角形来表示继承关系,一个类继承另一个类,被继承的类叫父类或者基类,另一个叫子类或者派生类。用空心三角形指向父类

例如: Stuent是人,有的一切属性和行为,Student继承自父类Human

Code of Student:

1
2
3
class Student extends Human{
int id;
}

Code of Human{

1
2
3
4
5
6
7
class Human{
String name;
int age;
void Speak(){
System.out.println("Hello");
}
}

泛化

实现关系

  • 在UML图中用虚线和空心三角形连接接口和实现接口的类。虚线的终点端是它实现的接口。
    例如: 笔记本是计算机的一种实现,只有有中央处理器,有输入输出设备就是一台计算机。

Code of Computer:

1
2
3
4
5
6
7
interface Computer{
String Cpu="x64";
String Input="Keyboard";
String Output="Monitor";

void Run();
}

Code of Laptop:

1
2
3
class Laptop implements Computer{
public void Run(){}
}

实现

常见的设计模式

简单工厂模式

例子

生产汽车🚘的工厂生产两种品牌的汽车,一种是宝马汽车,另一种汽车是🚗奥迪汽车。用户并不了解汽车是如何生产的,仅仅只是从工厂得到汽车。宝马汽车和奥迪汽车有相同的共性,都是汽车,均实现了汽车这个接口。

FactorySimple

Car:

1
2
3
interface Car {
void Run();
}

AodCar:

1
2
3
4
5
public class AodCar implements Car {
public void Run(){
System.out.println("奥迪汽车启动");
}
}

BmwCar:

1
2
3
4
5
public class BmwCar implements Car {
public void Run(){
System.out.println("宝马汽车启动");
}
}

FactorySimple:

1
2
3
4
5
6
7
8
9
public class FactorySimple {
public static Car Produce(String message){
switch(message){
case "宝马": return new BmwCar();
case "奥迪": return new AodCar();
default: return null;
}
}
}

Customer:

1
2
3
4
5
6
public class Customer {
public static void main(String args[]){
FactorySimple.Produce("宝马").Run();
FactorySimple.Produce("奥迪").Run();
}
}

工厂方法模式

开闭原则: 对拓展开放,对修改封闭. 一个软件的变化应该通过拓展来实现,而不是通过修改现有代码。

例子

FactoryMethod

只需要将简单工厂方法中的工厂抽象为接口,分别实现宝马工厂和奥迪工厂,客户端实例化这两个工厂。

Factory:

1
2
3
public interface Factory {
Car Produce();
}

BmwFactory:

1
2
3
4
5
public class BmwCar implements Car {
public void Run(){
System.out.println("宝马汽车启动");
}
}

AodFactory:

1
2
3
4
5
public class AodFactory implements Factory {
public Car Produce(){
return new AodCar();
}
}
优点 缺点
符合开闭原则和单一职责原则,拓展性比较强 增加一个产品时,需要增加一个产品类和具体子工厂,给系统增加负担的同时,每种工厂生产一种产品,太过单一

单例模式

  • 单例类只有一个实例,不能再外部被实例化
  • 单例类必须自己创建自己的唯一实例
  • 单例类必须给所有其他对象提供这一实例

实现方式

不能通过无参构造函数在外部实例化(私有构造),如何限制只有一个?(类的静态成员只有一个副本)

  • 饿汉式(立即加载)
    在类初始化时就构造好了一个静态对象供外部使用,除非系统重启,这个对象不会改变,所以本身就是线程安全的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class SingleHunger {
//饿汉式(立即加载)在编译完成时完成实例化
private SingleHunger(){

}

private static SingleHunger single = new SingleHunger(); //利用静态成员只有一个副本的特点来构造单例模式。

public static SingleHunger getInstance(){
return single;
}

int age;

public void Info(){
System.out.println("我是一个饿汉式的单例类的对象");
}
}

懒汉式(延迟加载)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class SingleLazy {

private SingleLazy(){

}

private static SingleLazy Single=null;

public static SingleLazy getInstance(){

if(Single==null){
// 1 2 3
synchronized(SingleLazy.class){
if(Single==null){
try{
Thread.sleep(10);
}
catch(InterruptedException e){
e.printStackTrace();
}
Single = new SingleLazy();
}

}

}

return Single;
}

public void Info(){
System.out.println("I am a single instance that made by the Lazy Single Class");
}
}

在多线程的情况下,这显然不是单例,这时候我们就需要将同步锁🔐加在合适的位置。

synchronizedstatic 一起使用,同步当前类。

使用 synchronized 同步锁此种方式解决了多个实例对象的问题,但是该种方式的执行效率较低,提高 sychronized 的效率需要尽可能的缩小同步的范围。

静态内部类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SingleInside {
private SingleInside(){}

private static class InSide{
private static SingleInside Single = new SingleInside();
}

public static SingleInside getInstance(){
return InSide.Single;
}

public static void Info(){
System.out.println("I am a single instance that made by Static Class insige");
}
}

优点:

  1. 在内存中

外观模式

例子

Facade

职责链模式

行为型模式:关注系统中对象之间的相互交互,通信与合作

  1. 责任链(职责)模式: Chain of respon

例子

策略模式

例子

场景: 某个市场的销售人员,接到单后的报价策略:

  • 普通用户小批量报价
  • 普通用户大批量报价
  • 老用户小批量报价
  • 老用户大批量报价

核心: 分离算法 选择实现

这些策略构成一个算法族。

Strategy:

1
2
3
4
5
6
7
8
9
10
/**
* 某市场销售人员针对不同的情况实行不同的报价策略:
* 1. 新用户小批量采购 不打折
* 2. 新用户大批量采购 打八五折
* 3. 老用户小批量采购 打八折
* 4. 老用户大批量采购 打六五折
*/
public interface Strategy {
void getPrice(double price);
}

NewCustomerFew:

1
2
3
4
5
6
7
8
9
/**
* 新用户小批量采购
*/

public class NewCustomerFew implements Strategy {
public void getPrice(double price){
System.out.println("不打折 "+price);
}
}

NewCustomerMany:

1
2
3
4
5
6
7
8
9
/**
* 新用户大批量采购
*/

public class NewCustomerMany implements Strategy {
public void getPrice(double price){
System.out.println("打八五折 "+price * 0.85);
}
}

OldCustomerFew:

1
2
3
4
5
6
7
8
9
/**
* 老用户小批量采购
*/

public class OldCustomerFew implements Strategy {
public void getPrice(double price){
System.out.println("打八折 "+price * 0.8);
}
}

OldCustomerMany:

1
2
3
4
5
6
7
8
9
/**
* 老用户大量采购
*/

public class OldCustomerMany implements Strategy {
public void getPrice(double price){
System.out.println("打六五折 "+price * 0.65);
}
}

Client:

1
2
3
4
5
6
7
8
9
10
11
/**
* 分离算法 分离实现
*/

public class Client {

public static void main(String args[]){
NewCustomerMany a = new NewCustomerMany();
a.getPrice(998);
}
}