NanYin的博客

记录生活点滴


  • Home

  • About

  • Tags

  • Categories

  • Archives

  • Search

PlantUML类图使用总结

Posted on 2019-06-26 | In 工具
Words count in article: 1.1k | Reading time ≈ 4

使用PlantUML绘制类图

本文基于PlantUML官网绘制类图和相关如何正确uml类图相关文章。

为什么使用plantUml

原因很简单,不用自己考虑构图,像写代码一样写出来,图出来既美观又能够符合逻辑。

基本类构成

基本使用

基本类构成

使用class关键字构件类,同理其他关键字。如interface,enum。

在类中使用 - # + 分别对应表示类中的private,protected,public。如果在类中使用 static、abstract关键字,需要使用大括号包裹起来。

备注使用note来实现,可以使用js优化备注的样式,具体可以参考下面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@startuml
' 简单定义类A
class classA
'定义类B
class classB{
-{static} STATIC:Type
-a:A
#b:B
+c:C
+hello():void
-word():void
}
'抽象类C
abstract class classC {
+ {abstract} method1:void
}
'备注
note right: note on right
note top of classA : note on top
' 复杂备注
note top of object
In java, <size:18>every</size> <u>class</u><b>extends</b><i>this</i> one.
end note
@enduml

类更多使用

复杂

更复杂一些的类的构件参考上图。

使用__内容__来表示分割线,对不同类型的进行分割。在类名后加<? extends xxx> 表示范型,参考下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@startuml
class classC <<Serializable>> {
__variable__
-a:A
#b:B
+c:C
__methods__
+hello():void
-word():void
}

class classD <? extends List>{

}
@enduml

关系表示

继承与实现

继承与实现

继承指的就是泛化,如图中左表示一样,类A继承于B,由子类实现父类的行为。泛化使用带大三角箭头和实线来表示,表示一种继承关系。

实现指的是特定类实现接口,如图中右表示一样,类implement实现interface,表示实现类实现接口类的关系。同样会由子类实现接口类中的行为。实现使用带大三角的箭头和虚线来实现。

无论是继承还是实现,箭头都执行夫类,也就是被实现类。

依赖与关联

依赖与关联

使用plantUML代码实现:

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
@startuml
'依赖与关联
Class X
' 依赖关系
X ..> Y :"依赖关系"

class A
' 单向关联 A关联B
A--> B :"单向关联"
' 双向关联
class C
C -- D : "双向关联"
' 自关联
class F
F --> F:"自关联"
' 聚合关系
class G {
List<H> h
}
G "n" o-- "1" H : "组合关系"
' 组合关系
class K {
List<L> l
}
K "n"*--"1" L :"聚合关系"
@enduml
一、依赖关系

依赖是一种使用的关系,代码中体现到依赖的关系的情况:局部变量、方法的参数或者对静态方法的调用,依赖是最弱的一种关联。依赖关系使用虚线和普通的小箭头来实现,箭头指向被依赖的对象。如图中的x依赖y一样,所以指向y,这个被x依赖的对象。

二、关联关系

关联是拥有的关系,如玩家与游戏中的角色一样。关联可能是单向的,也可能是双向的,也同样能够自己关联自己。代码中体现到关联的关系的情况:成员变量。关联关系使用实线和小尖头来实现,箭头指向被关联的对象。

三、组合关系

组合关系是整体与部分的关系,但是如果整体不存在,那部分也不能存在。就如同公司与部门一样,公司解散了,部门也就不存在了。和关联关系相同,在代码中的体现也是成员变量。组合关系使用空心的菱形和实线来表示。

四、聚合关系

聚合关系是整体与部分的关系,但是和组合关系不同的是,聚合关系中的部分可以脱离整体而存在,就如同麦当劳中的套餐与汉堡一样。在代码中的体现同样是成员变量。聚合关系使用实心的菱形和实线来表示。

所以可以说聚合关系和组合关系是关系更加确定,更加紧密的关联关系。

各关系的强弱顺序

泛化= 实现> 组合> 聚合> 关联> 依赖

PlantUML支持更多的更复杂的情景下的图形绘制,具体可以查看PlantUML的中文网站。

设计模式之备忘录模式

Posted on 2019-06-25 | In 设计模式
Words count in article: 647 | Reading time ≈ 2

设计模式之备忘录模式📕

不违反封装的情况下,捕获并外化对象的内部状态,以便稍后可以将对象恢复到此状态。

应用场景

必须保存对象状态的快照,以便以后可以将其恢复到该状态

模式结构

模式结构分为三种结构:

  1. 发起人 (Originator)
    负责创建一个有内部状态的备忘录对象。
  2. 负责人 (Caretaker)
    负责保存备忘录内容,但是不检查备忘录的内容。
  3. 备忘录 (Memento)
    保存发起人的内部的状态。

模式结构

上图中的ActionGame为负责人,负责保存状态,Player为发起人负责主动记录备忘录。

实际场景

在玩单机游戏的时候,在通过一个关卡的时候,系统会记录你当时的状态信息,如果下一关没通过,会自动还原到上一个记录点从新开始。这种情况下就可以使用备忘录模式记录存档状态,并在适当的时候还原状态。针对此处场景,使用下面代码还原。

代码

作为发起者的Player

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
public class Player {
// 游戏状态
private GameState gameState;

Player(GameState gameState) {
this.gameState = gameState;
}

// 设置状态
void setGameState(GameState gameState) {
this.gameState = gameState;
}

//获取状态
GameState getGameState() {
return gameState;
}

// 创建存档记录
Memento createMemento(){
return new Memento(gameState);
}
// 回退存档记录
void retrieveMemento(Memento memento){
this.gameState = memento.getGameState();
}

}

作为负责人的ActionGame

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
public interface Game {
void storeGamePoint(Memento memento);
Memento retrieveGamePoint();
}

public class ActionGame implements Game {

private Memento memento;
/**
* 存档记录
* @Author nanyin
* @Date 17:31 2019-06-26
* @param memento 1
* @return void
**/
@Override
public void storeGamePoint(Memento memento) {
this.memento = memento;
}
/**
* 还原记录点
* @Author nanyin
* @Date 17:32 2019-06-26
* @return Memento
**/
@Override
public Memento retrieveGamePoint() {
return this.memento;
}
}

作为备忘录的Memento

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Memento {
private GameState gameState;
Memento(GameState gameState) {
this.gameState = gameState;
}

GameState getGameState() {
return gameState;
}
}

public enum GameState {
DIE,SUCCESS
}

客户端程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class App {
public static void main(String[] args) {
//创建一个动作类型的游戏
Game actionGame = new ActionGame();
//玩家通关
Player player = new Player(GameState.SUCCESS);
//存档
Memento memento = player.createMemento();
actionGame.storeGamePoint(memento);
//此时玩家阵亡
player.setGameState(GameState.DIE);
System.out.println(player.getGameState());
//需要从上一次游戏存档中加载原来的玩家状态
player.retrieveMemento(actionGame.retrieveGamePoint());
System.out.println(player.getGameState());
}
}

在游戏存档后死亡,再重复读存档,得到之前存档之前的状态。游戏不会主动存档和读取存档,只会记录存档中的内容,而玩家会主动从游戏中读取存档,然后恢复到存档的状态。

设计模式之观察者模式

Posted on 2019-06-19 | In 设计模式
Words count in article: 889 | Reading time ≈ 3

设计模式之观察者模式

观察者模式是对象的行为模式,又叫“发布-订阅模式”。由名字就能够得知,观察这模式构造了一个发布者和订阅者。

观察者模式定义对象之间的一对多依赖关系,以便当一个对象更改状态时,将自动通知和更新其所有依赖项。在观察者模式中,主动发生改变的是发布者称为主题,而被动收到发布者信息的订阅者称为观察者对象,可以根据需要添加/减少具体主题的观察者,实现主题和观察者之间的松耦合。

应用场景

  • 当设计中有两种不同方面的抽象,并且是有依赖关系的,这时将两个抽象分别封装到具体的类中,这样就能够独立的改变和重用这些对象。在观察者模式中两种抽象指的就是抽象主题和抽象观察者。

  • 当一个对象需要更改时,涉及到更改其他类型的其他对象,并且这些对象的数量多且不确定的时候。

  • 当一个对象改变时,其他对象能够得到这个对象已经改变的通知,而不必知道这些对象具体是什么。也就是说要达到这个改变的对象和通知的对象的松耦合。

    所以综上:
    当希望一个对象改变的同时,多个对象能够得到通知,一块进行变更时,可以使用观察者模式对系统设计

模式结构

观察者模式结构图

上图中:

  1. Weather为抽象主题类,能够将观察者Observer构成一个list结构,从而能够达到Weather改变的时候可以循环表中的观察者,发送通知。并且作为抽象类实现了添加,移除观察者方法。
  2. BeijingWeather为具体主题类,实现了Weather类。
  3. Observer作为抽象观察者类,作为所有观察者的通用接口,其中定义update方法作为更新状态的接口。通过这个接口和Weather类交互来获取状态通知。
  4. WeatherObserverA与WeatherObserverB作为具体观察者类,实现类观察者接口。统一接受通知并更新自身状态。

代码

第一部分:抽象主题类

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
// 状态枚举类
public enum WeatherState {
SUNNY_DAY,
CLOUDY_DAY,
RAINY_DAY,
}
// 抽象主题类
public abstract class Weather {

protected WeatherState weatherState;
// 观察者集合
private List<Observer> observerList = new ArrayList<>();

public Weather addObserver(Observer observer){
observerList.add(observer);
return this;
}

public void removeObserver(Observer observer){
observerList.remove(observer);
}

// 通过主题更改从而在该主题上注册的观察者能够同时能到通知
public void notifyObserver(){
for (Observer o:observerList
) {
o.update(this.weatherState);
}
}
}

第二部分:具体主题类

1
2
3
4
5
6
7
8
9
10
public class BeijingWeather extends Weather {

BeijingWeather(WeatherState weatherState) {
this.weatherState = weatherState;
}
//作为更新主题的接口
public void changeState(WeatherState we){
this.weatherState = we;
}
}

第三部分:抽象观察者

1
2
3
4
public interface Observer {
// 更新接口
void update(WeatherState weatherState);
}

第四部分: 具体观察者

1
2
3
4
5
6
public class WeatherObserverA implements Observer {
@Override
public void update(WeatherState weatherState) {
System.out.println("observer A get new weather message is " + weatherState.toString());
}
}

最后调用

1
2
3
4
5
6
7
8
9
10
public class App {
public static void main(String[] args) {
// 定义主题
Weather weather = new BeijingWeather(WeatherState.SUNNY_DAY);
//添加观察者
weather.addObserver(new WeatherObserverA()).addObserver(new WeatherObserverB());
//通知所有观察者
weather.notifyObserver();
}
}

结果:最后注册在主题上的所有观察者都收到了通知。

1
2
observer A get new weather message is SUNNY_DAY
observer B get new weather message is SUNNY_DAY

设计模式之状态模式

Posted on 2019-06-19 | In 设计模式
Words count in article: 575 | Reading time ≈ 2

设计模式之状态模式

状态模式是对象的行为模式。状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。

应用场景

  • 对象的行为取决于其状态,并且必须根据该状态在运行时更改其行为。
  • 通常,几个操作将包含相同的条件结构。State模式将条件的每个分支放在一个单独的类中。可以将对象的状态视为一个对象,它可以独立于其他对象而变化

概括来说,状态模式将行为包装到具体的状态对象中。每个状态对象是抽象状态的子类。状态模式意图是在改变对象的内部状态的时候,行为随之改变。

模式结构

状态模式分为三种结构:环境角色、抽象状态角色、具体状态角色

状态模式结构图

代码

电灯有两种基本行为 开启、关闭。但是有两个状态,正常和坏掉的状态。将共同的行为封装到统一的状态接口中,再根据不同的状态,创建子类完成不同状态形成不同的行为。

灯再正常状态下能够正常开启,正常关闭。等在坏掉的状态下,不能开启和关闭。状态模式就是根据这个逻辑抽离行为,将具体行为包装到具体状态对象中。

抽象状态角色

1
2
3
4
public interface State {
void open();
void close();
}

具体状态角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class NormalState implements State{
@Override
public void open() {
System.out.println("电灯开了!");
}

@Override
public void close() {
System.out.println("电灯关了!");
}
}

public class ErrorState implements State {
@Override
public void open() {
System.out.println("电灯开不了!");
}

@Override
public void close() {
System.out.println("电灯关不了!");
}
}

环境角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Context {
//状态参数
State state;
public Context(State state) {
this.state = state;
}

public void requestToOpen() {
state.open();
}

public void requestToClose() {
state.close();
}
//状态变化
public void changeStageTo(State state){
this.state = state;
}
}

客户端测试

1
2
3
4
5
6
7
8
9
10
11
public class App {
public static void main(String[] args) {
Context context = new Context(new NormalState());
context.requestToOpen();
context.requestToClose();
//将状态变更为坏的状态
context.changeStageTo(new ErrorState());
context.requestToOpen();
context.requestToClose();
}
}

Mac下使用idea时在dock栏一直存在java图标和控制台乱码问题

Posted on 2019-06-18 | In 工具
Words count in article: 112 | Reading time ≈ 1

Mac下使用Idea相关问题

使用tomcat启动IDEA项目后,dock栏一直存在JAVA图标问题

在mac上启动idea后,存在dock栏一直存在JAVA图标的问题,如下图:

Dock栏存在java图标问题

解决方式:

存在图标解决方式

打开Run/Debug configurations,在vm options中添加如下内容:

1
-Dapple.awt.UIElement=true

启动IDEA后,控制台乱码

控制台乱码

解决方式和上一个问题相同,同样在vm options中增加参数,具体参数如下:

1
-Dfile.encoding=UTF-8

设计模式之模版模式

Posted on 2019-06-17 | In 设计模式
Words count in article: 820 | Reading time ≈ 3

设计模式之模版方法模式

模版模式是类的行为模式,将部分逻辑以具体方法来实现,将其他方法声明为抽象方法来让子类来实现。不同的子类实现的方法逻辑不同,从而整体的逻辑有所差异。

这里涉及到两个角色:

一、抽象模板(Abstract Template)角色有如下责任:

- 定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,
它们是一个顶级逻辑的组成步骤。

- 定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,
而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。

二、具体模板(Concrete Template)角色又如下责任:

- 实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤。

- 每一个抽象模板角色都可以有任意多个具体模板角色与之对应,
而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,
从而使得顶级逻辑的实现各不相同。

应用场景

实现不变的部分一次,并将其他留给子类来实现可能需要变化的行为。

  • 需要简化代码,分离出公共的部分,抽离出一个公共的模板方法来替换所有的代码。
  • 控制子类扩展。定义在特定点调用“钩子”操作的模板方法,从而仅允许在那些点进行扩展。

模式结构

这里使用到模拟servlet中的httpServlet方法(简单的模拟方法中用到的模版方法)。定义一个公共的模版方法抽象类HttpServletTemplate,其中有两个钩子方法doGet和doPost,所谓的钩子方法就是需要由子类实现的方法。还有一个具体方法service来实现模版调用的作用。

模拟两个子类实现HttpServletTemplate实现两个钩子方法。

客户端App在调用的时候,直接调用两个子类的父类中的实现方法service实现调用模版。

模版模式结构

代码

抽象模版类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class HttpServletTemplate {

public void service(HttpRequestMethod method){
if(method.equals(HttpRequestMethod.METHOD_GET)){
System.out.println("so something 1");
doGet();
System.out.println("so something 2");
}else if(method.equals(HttpRequestMethod.METHOD_POST)){
doPost();
}else {
System.out.println("do nothing!");
}
}
protected void doGet(){};

protected void doPost(){};
}

具体模版类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class GetClient extends HttpServletTemplate {
@Override
protected void doGet() {
System.out.println("this is my get methods!");
}
}
public class PostClient extends HttpServletTemplate {
@Override
protected void doGet() {
this.doPost();
}

@Override
protected void doPost() {
System.out.println("this is my post methods!");
}
}
// 请求类型枚举类
public enum HttpRequestMethod {
METHOD_GET,METHOD_POST,METHOD_DELETE
}

客户端调用

1
2
3
4
5
6
7
8
9
10
11
public class App {
public static void main(String[] args) {
//声明post客户端
PostClient post = new PostClient();
//调用模版
post.service(HttpRequestMethod.METHOD_POST);
GetClient get = new GetClient();
get.service(HttpRequestMethod.METHOD_GET);
get.service(HttpRequestMethod.METHOD_POST);
}
}

其实模版方法模式是创建一个算法的骨架,具体的内容由子类去填充的这个过程。

设计模式之访问者模式

Posted on 2019-06-15 | In 设计模式
Words count in article: 1.1k | Reading time ≈ 4

设计模式之访问者模式

访问者模式是一种复杂的行为模式。表示要对对象结构的元素执行的操作。访问者允许对对象结构中的节点定义新操作,而无需更改其操作的元素的类。

适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。

应用场景

当遇到如下情况时,可以优先考虑使用访问者模式:

  1. 对象结构中包含许多具有不同接口的对象类,并且希望对依赖于其具体类的这些对象执行操作。
  2. 需要对对象结构中的对象执行许多不同且不相关的操作,并且希望避免使用这些操作“污染”它们的类。这时就可以定义多个visitor类来完成对多个对象节点的处理。
  3. 定义对象结构的类很少改变,但是你经常想要在结构上定义新的操作。

模式结构

举个例子:在公司中,需要统计打卡记录和绩效,分别有行政部门和财务部门来实现。并且将来可能有质量部门监测研发和实施人员的工作质量。但是对研发和实施人员的考核标准有所不同。

一、类图

类图

OperateStructure作为对象OperateNode的数据结构,并且实现类OperateNodeA和OperateNodeB行为方法有各自的实现。并且想基于这个相对固定的数据结构实现多种不同的操作(visitor)。这样在增加visitor的时候不必考虑数据结构会发生变更。

二、时序

由于调用过程比较不容易看透,这里我先使用时序图来说明调用顺序

调用过程时序

代码实例

根据类图可以看出,访问者模式分为五部分:抽象节点角色 、具体节点角色 、抽象访问者角色 、具体访问者角色 、结构对象角色

  • 抽象节点角色:
1
2
3
4
public abstract class OperateNode {
// 定义节点内都需要实现的方法
abstract void accept(Visitor visitor);
}
  • 具体节点角色:
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 具体节点A 在实例中对应研发人员
class OperateNodeA extends OperateNode {
//绩效系数
private static final double COEFFICIENT = 1.2;

private int workDate;

OperateNodeA(int workDate) {
this.workDate = workDate;
}

@Override
void accept(Visitor visitor) {
visitor.visit(this);
}

int attendance(){
return workDate;
}

double performance(){
return workDate * COEFFICIENT;
}
}
// 具体节点B,在实例中对应运维人员
class OperateNodeB extends OperateNode {

private static final int COEFFICIENT = 1;

private int workDate;

OperateNodeB(int workDate) {
this.workDate = workDate;
}

@Override
void accept(Visitor visitor) {
visitor.visit(this);
}

int attendance(){
return workDate;
}

double performance(){
return workDate * COEFFICIENT;
}
}
  • 抽象访问者角色
1
2
3
4
5
//针对结构中每一个节点分别进行各自的操作
public interface Visitor {
void visit(OperateNodeA operateNodeA);
void visit(OperateNodeB operateNodeB);
}
  • 具体访问者角色
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
// 行政人员结算考勤
public class VisitorA implements Visitor {
// 需要对实施人员增加路上的考勤时间 模式为2
private static final int BASIC = 2;
@Override
public void visit(OperateNodeA operateNodeA) {
int att = operateNodeA.attendance();
System.out.println("本月该研发人员考勤为"+att + "天");
}

@Override
public void visit(OperateNodeB operateNodeB) {
int att =operateNodeB.attendance() + BASIC;
System.out.println("本月该实施人员考勤为"+att + "天");
}
}
//财务人员结算绩效
public class VisitorB implements Visitor {
// 研发需要添加额外绩效
private static final int EXTRA = 2;
@Override
public void visit(OperateNodeA operateNodeA) {
double att = operateNodeA.performance() + EXTRA;
System.out.println("本月该研发人员绩效为 :"+att );
}

@Override
public void visit(OperateNodeB operateNodeB) {
double att =operateNodeB.performance() ;
System.out.println("本月该研发人员绩效为 :"+att );
}
}
  • 结构对象结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class OperateStructure {
// 定义结构体
private List<OperateNode> list = new ArrayList<>();

void add(OperateNode operateNode){
list.add(operateNode);
}
//对结构体中的对象实现接收访问操作
void action(Visitor visitor){
for (OperateNode operateNode : list){
// 目的就是使用双重分派调用来实现
// 节点接受访问者与访问者访问节点的操作
operateNode.accept(visitor);
}
}
}
  • 客户端调用
1
2
3
4
5
6
7
8
9
10
11
public class App {
public static void main(String[] args) {
Visitor visitorA = new VisitorA();
Visitor visitorB = new VisitorB();
OperateStructure structure = new OperateStructure();
structure.add(new OperateNodeA(22));
structure.add(new OperateNodeB(22));
structure.action(visitorA);
structure.action(visitorB);
}
}
  • 结果
1
2
3
4
本月该研发人员考勤为22天
本月该实施人员考勤为24天
本月该研发人员绩效为 :28.4
本月该研发人员绩效为 :22.0

设计模式之代理模式

Posted on 2019-06-14 | In 设计模式
Words count in article: 604 | Reading time ≈ 2

设计模式之代理模式

代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

应用场景

  1. 远程代理不同地址空间的对象,都当作本地化对象来处理
  2. 控制对象的访问权限。

当遇到一下情况是可以使用代理模式:

  • 想控制对另一个对象的访问
  • 懒加载
  • 控制日志输出
  • 计算对象引用
  • 控制网络链接问题

代理模式模式结构

浴室分为男浴室和女浴室,其中前台判断能够进入浴室的前提是没有皮肤病,如有没有,才让进入浴室。这里的前台就是一个代理,它代理来浴室,用来判断能否进入浴室的权限。这就是代理的作用。

代理模式和装饰者模式比较容易混淆。需要记住的是,两者的功能区别在于,代理模式改变的是对象的职能,控制对象的行为。而装饰者模式是对职能的增加和减少。使用场景上有所不同。

代理模式结构图

代码

代理模式大致能够分为三部分:抽象职能类,代理类,被代理类

第一部分:抽象职能类

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
35
36
// Person 基本信息类 和性别枚举 
public class Person {
private String name ;

private SexEnum sex;
//是否有皮肤病
private int hasSkinDisease;

public Person(String name, SexEnum sex, int hasSkinDisease) {
this.name = name;
this.sex = sex;
this.hasSkinDisease = hasSkinDisease;
}

public String getName() {
return name;
}

public SexEnum getSex() {
return sex;
}

public int getHasSkinDisease() {
return hasSkinDisease;
}
}

public enum SexEnum {
MALE,FEMALE
}

//抽象职能
abstract class BathRoom {
// 去澡堂泡澡
abstract BathRoom enterBathroom(Person person);
}

第二部分:被代理类

1
2
3
4
5
6
7
8
9
10
11
public class MaleBathRoom extends BathRoom {
@Override
public BathRoom enterBathroom(Person p) {
String sexName = "";
if(SexEnum.MALE.equals(p.getSex())){
sexName = SexEnum.MALE.toString();
System.out.println("name : "+ p.getName() +" sex: "+ sexName +" go bath for male !");
}
return this;
}
}

第三部分:代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

public class BathRoomProxy extends BathRoom {

BathRoom bathRoom;

public BathRoomProxy(BathRoom bathRoom) {
this.bathRoom = bathRoom;
}

@Override
public BathRoom enterBathroom(Person person) {
if (person.getHasSkinDisease() == 0) {
this.bathRoom.enterBathroom(person);
} else {
System.out.println(person.getName() + " has disease.");
}
return this;
}
}

客户端调用:

1
2
3
4
5
6
7
8
9
public class App {
public static void main(String[] args) {
Person p1 = new Person("1",SexEnum.MALE,0);
Person p2 = new Person("2",SexEnum.MALE,1);

BathRoomProxy bathRoomProxy = new BathRoomProxy(new MaleBathRoom());
bathRoomProxy.enterBathroom(p1).enterBathroom(p2);
}
}

结果:

1
2
name : 1 sex: MALE go bath for male !
2 has disease.

设计模式之享元模式

Posted on 2019-06-13 | In 设计模式
Words count in article: 827 | Reading time ≈ 3

设计模式之享元模式

享元模式是对象的结构模式。享元模式以共享的方式高效地支持大量的细粒度对象。它用于通过尽可能多地与类似对象共享来最小化内存使用或计算开销。

应用场景

  1. 应用中需要大量的对象,大量的对象可能造成存储对象的开销。
  2. 对象变化的状态大多是外部状态。一旦外部状态被移除,许多对象组可被相对较少的共享对象替换。这也就是享元模式利用的点。
  3. 因为在享元模式中对象是共享的,所以在含义上的不同对象使用equels实际返回的是true。

享元模式结构

享元模式采用一个共享来避免大量拥有相同内容对象的开销。这种开销最常见、最直观的就是内存的损耗。享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。

内蕴状态决定对象本身的状态,不会随着环境的变化而变化,而外蕰状态是由客户端将状态传递给享元对象的,外蕴状态类似同一个对象的不同的行为,内蕴状态和外蕰状态是相互独立,互不影响的。

享元模式主要这几三个部分:抽象享元类,具体享元类和享元工厂类。具体可以参考下面代码。

享元模式

代码

在Java中,String类就符合享元模式,string a = "aa" 和 string b ="aa" 是相等的。

在下面例子中,构造抽象享元类“MyString” 和它的具体实现类,使用到相同的对象,因为享元模式,可以对这些对象进行共享使用。

第一部分:抽象享元类

1
2
3
4
5
6
7
public interface MyString {
void create(String outerState);
}
//枚举类
public enum InstanceType {
INSTANCE1,INSTANCE2
}

第二部分:具体享元类

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
public class StringIns1 implements MyString {

// 内部状态,不可随时变化的
String innerState;

public StringIns1(String innerState) {
this.innerState = innerState;
}

@Override
public void create(String outerState) {
System.out.println("create instance 1 -> innerState:"+this.innerState);
//外部状态,需要客户端传进来,这个值是可变化的
System.out.println("create instance 1 -> outerState:"+outerState);
}
}

public class StringIns2 implements MyString {

String innerState;

public StringIns2(String innerState) {
this.innerState = innerState;
}

@Override
public void create(String outerState) {
System.out.println("create instance 2 -> innerState:"+this.innerState);
System.out.println("create instance 2 -> outerState:"+outerState);
}
}

第三部分:享元工厂类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class FlyWeight {
Map<InstanceType,MyString> store;

FlyWeight() {
store = new HashMap<>();
}

public MyString factory(InstanceType instanceType){
MyString curr = store.get(instanceType);
if(curr == null){
// 如果对象不存在,新建对应的对象
if(instanceType.equals(InstanceType.INSTANCE1)){
// 根据内部状态决定生成哪个类型的子类
curr= new StringIns1(instanceType.toString());
} else if(instanceType.equals(InstanceType.INSTANCE2)){
curr= new StringIns2(instanceType.toString());
}
}
store.put(instanceType,curr);
return curr;
}
}

第四部分:客户端调用

1
2
3
4
5
6
7
8
9
10
public class App {
public static void main(String[] args) {
FlyWeight flyWeight = new FlyWeight();
MyString ins1 = flyWeight.factory(InstanceType.INSTANCE1);
MyString ins2 = flyWeight.factory(InstanceType.INSTANCE1);
System.out.println(ins1.equals(ins2));//true 是同一个对象 内部状态相同
ins1.create("*****"); //针对外部状态打印不同内容
ins2.create("-----");
}
}

结果:

1
2
3
4
5
true
create instance 1 -> innerState:INSTANCE1
create instance 1 -> outerState:*****
create instance 1 -> innerState:INSTANCE1
create instance 1 -> outerState:-----

设计模式之外观模式

Posted on 2019-06-12 | In 设计模式
Words count in article: 596 | Reading time ≈ 2

设计模式之外观模式

外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,使子系统更容易使用。

应用场景

  • 因为子系统随着发展会变更的更复杂,客户端想更简单统一给子系统建立一个公共的调用方式。这样即使子系统的再增加可重用性而变得更加复杂,客户端也不必知道,因为客户端往往不需要针对某一个子系统进行特定的定制化。
  • 实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户类,只需要调整外观类即可。

模式结构

外观模式中客户端依靠Facade类来调用多个子系统,来达到简化客户端调用的目的。

外观模式

例子中,每次开机的时候都要启动mysql,apache服务,两个还好,要是有更多服务岂不是很恼人,每次都要敲一大堆命令来开启服务。这时候可以使用外观模式,将所有服务加入到外观类中,每次开机只用调用外观类中的接口就行了。来达到简化客户端使用的目的。

代码

第一部分:子系统接口

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
35
36
37
38
39
public interface Services {
void start();
void stop();
void restart();
}
// mysql 服务
public class MysqlService implements Services {
@Override
public void start() {
System.out.println("mysql is started");
}

@Override
public void stop() {
System.out.println("mysql is stopped");
}

@Override
public void restart() {
System.out.println("mysql is restart");
}
}
// apache 服务
public class ApacheService implements Services {
@Override
public void start() {
System.out.println("apache is started");
}

@Override
public void stop() {
System.out.println("apache is stopped");
}

@Override
public void restart() {
System.out.println("apache is restart");
}
}

第二部分:外观类

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
public class Facade {
List<Services> services;

public Facade() {
services = new ArrayList<>();
}

public void addService(Services services){
this.services.add(services);
}

public void start(){
for (Services services : this.services){
services.start();
}
}

public void stop(){
for (Services services : this.services){
services.stop();
}
}

public void restart(){
for (Services services : this.services){
services.restart();
}
}
}

第三部分:客户端调用

1
2
3
4
5
6
7
8
9
public class App {
public static void main(String[] args) {
Facade facade = new Facade();
facade.addService(new MysqlService());
facade.addService(new ApacheService());
facade.start();
facade.stop();
}
}

结果:

1
2
3
4
mysql is started
apache is started
mysql is stopped
apache is stopped
<i class="fa fa-angle-left"></i>1…456…12<i class="fa fa-angle-right"></i>
NanYin

NanYin

Was mich nicht umbringt, macht mich starker.

111 posts
16 categories
21 tags
RSS
GitHub E-Mail
近期文章
  • ThreadLocal
  • Java的四种引用类型
  • Markdown语法入门
  • IDEA设置代码注释模板和JavaDoc文档生成
  • 基于Java的WebService实践
0%
© 2023 NanYin
|
本站访客数:
|
博客全站共140.1k字
|