现在越来越多年轻人不讲武德,明明是java面向对象程序员,但是天天写着面向过程的代码。你和他们谈编程范式、设计原则,设计模式,他们会说不就一个简单的if/else吗,用什么设计模式,搞那么复杂!不是闲的,是你的认知水平不够。设计模式站在软件设计层面,不仅为了解决眼前业务,更多的是软件复用性、可读性、扩展性、可靠性、高内聚、低耦合。先来了解一下常用的设计原则有哪些?
下面我们先通过一个简单案例来解读设计模式背后常用的设计原则。
现有一个资讯类APP,资讯分多个频道,需统计每个频道(如:篮球频道、足球频道、WWE频道)下,不同资讯类型(如:图文资讯、图集资讯、视频资讯)的点赞数、阅读数、收藏数。
设计需满足后续可以动态扩展资讯频道和资讯类型且改动尽量少,如再添加一个资讯频道叫“视频频道”,则设计需满足可以计算“视频频道“的图文、图集、视频资讯的点赞/阅读/收藏数,或者再添加一种资讯类型叫“娱乐资讯”,对应每个资讯频道也需统计该类资讯的点赞/阅读/收藏数。
资讯频道和资讯类型都有可能变化,那么让资讯频道和资讯类型充分解耦,让其各自可以独立变化,最后通过聚合的方式使二者产生调用关系。此处场景适合桥接模式,让抽象和具体实现进行分离,各自独立变化。此案例中,不同的资讯频道就是我们的抽象,不同的资讯类型就是我们对点赞/阅读/收藏数的不同具体实现。
public interface INewsStatistics {
NewsTypeEnum type();
Integer readCount(Long channelId);
Integer likeCount(Long channelId);
Integer collectCount(Long channelId);
}
先定义资讯统计接口 INewsStatistics
@Service
@RequiredArgsConstructor
public class ImageNewsStatistics implements INewsStatistics {
private final NewsMapper newsMapper;
@Override
public NewsTypeEnum type() {
return NewsTypeEnum.IMAGE;
}
@Override
public Integer readCount(Long channelId) {
return newsMapper.readCount(channelId);
}
@Override
public Integer likeCount(Long channelId) {
return newsMapper.likeCount(channelId);
}
@Override
public Integer collectCount(Long channelId) {
return newsMapper.collectCount(channelId);
}
}
定义图集资讯统计实现类
@Service
@RequiredArgsConstructor
public class InfoNewsStatistics implements INewsStatistics {
private final NewsMapper newsMapper;
@Override
public NewsTypeEnum type() {
return NewsTypeEnum.INFO;
}
@Override
public Integer readCount(Long channelId) {
return newsMapper.readCount(channelId);
}
@Override
public Integer likeCount(Long channelId) {
return newsMapper.likeCount(channelId);
}
@Override
public Integer collectCount(Long channelId) {
return newsMapper.collectCount(channelId);
}
}
定义图文资讯统计实现类
@Service
@RequiredArgsConstructor
public class VideoNewsStatistics implements INewsStatistics{
private final NewsMapper newsMapper;
@Override
public NewsTypeEnum type() {
return NewsTypeEnum.VIDEO;
}
@Override
public Integer readCount(Long channelId) {
return newsMapper.readCount(channelId);
}
@Override
public Integer likeCount(Long channelId) {
return newsMapper.likeCount(channelId);
}
@Override
public Integer collectCount(Long channelId) {
return newsMapper.collectCount(channelId);
}
}
定义视频资讯统计实现类
public abstract class Channel {
private List iNewsStatistics;
public Channel(List iNewsStatistics) {
this.iNewsStatistics = iNewsStatistics;
}
protected Map readCount(Long channelId) {
return iNewsStatistics.stream()
.collect(Collectors.toMap(statistics -> statistics.type(), statistics -> statistics.readCount(channelId)));
}
protected Map likeCount(Long channelId) {
return iNewsStatistics.stream()
.collect(Collectors.toMap(statistics -> statistics.type(), statistics -> statistics.likeCount(channelId)));
}
protected Map collectCount(Long channelId) {
return iNewsStatistics.stream()
.collect(Collectors.toMap(statistics -> statistics.type(), statistics -> statistics.collectCount(channelId)));
}
}
定义频道Channel 抽象类,并聚合iNewsStatistics资讯统计接口
@Service
public class BasketballChannel extends Channel {
private List iNewsStatistics;
public BasketballChannel(List iNewsStatistics) {
super(iNewsStatistics);
}
@Override
public Map readCount(Long channelId) {
return super.readCount(channelId);
}
@Override
public Map likeCount(Long channelId) {
return super.likeCount(channelId);
}
@Override
public Map collectCount(Long channelId) {
return super.collectCount(channelId);
}
}
定义频道Channel 抽象类的具体实现类BasketballChannel 篮球频道,对应的其他FootballChannel足球频道、WWEChannel频道类似,此处省略。使用时只需前端传入对应频道ID,调用对应频道的readCount、likeCount、collectCount方法,即可查询该频道下不同资讯类型的阅读/点赞/收藏数。