文字参考:https://www.bilibili.com/video/av24176315
代码参考:https://www.github.com/anxpp/JavaDesignPattern
变化是复用最大的天敌,面向对象编程最大的优势是抵御变化。需要将这种优势发挥出来就需要我们遵循设计原则,设计原则通常相辅相成,违反一个设计原则就违反了其他的设计原则。设计模式的设计就遵循设计原则。在学习设计模式的时候,我们需要回归设计原则。
在学习设计模式的过程中需要有意识的去发现代码中稳定的部分和变化的部分,在变化点处应用设计模式。几乎所有的设计模式都是用于有稳定又有变化的代码,因为如果完全稳定或者完全需要变化的代码根本没有使用设计模式的必要性。另外我们需要认识的是,我们没有办法消灭变化,只是将变化集中到一个地方,这样控制起来会比较容易,就像一直猫,原来在屋子里跑来跑去,现在我们将它关在了一个笼子里。
在什么时候,什么地方使用设计模式非常重要,对于设计模式的学习有的时候我们需要谨防“走火入魔”,比如接到需求的时候一上来就使用设计模式,如果不是特别有经验的程序员,这不是推荐的做法,因为这可能会导致你使用了错误的设计模式,从而使工作陷入困境之中。更推荐的做法是按照我们第一反应去写完需求,在检查代码的时候,会发现我们也许违背了一些设计原则或者一些经验不允许的代码结构(比如代码中出现if else结构,我们需要考虑是否可以使用策略模式),而这些问题可以使用设计模式去修正。所以更加推荐的做法是在代码演化的过程中使用模式,而不是一上来就直接到模式,除非你有足够的自信。
最后在学习设计模式的过程中看代码一定要有高度,和抽象思维,这对于理解和使用设计模式是非常有帮助的。
重构中我们通常可以使用以下的技法:
1. 依赖倒置原则(DIP)
2. 开放封闭原则(OCP)
3. 单一职责原则(SRP)
4. Liskov 替换原则(LSP)
5. 接口隔离原则(ISP)
6. 优先使用对象组合,而不是类继承
7. 封装变化点
8. 针对接口编程,而不是针对实现编程
以下的分类并不是绝对的,只是这种模式在这个分类特点中表现的最为明显。
组件协作:
单一职责:
对象创建:
对象性能:
接口隔离:
状态变化:
数据结构:
行为变化:
领域问题:
动机(Motivation)
模式定义
要点总结
在代码中我们的抽象类已经将处理逻辑(dealData()函数)实现了或者说固定了,但是却不知道getData()
和calcData()
的实现或者说需要子类实现。
public abstract class AbstractTemplate {
Object data;
//模板方法
void dealData(){
getData();
calcData();
printData();
}
//下面是普通方法,可能已经实现,也可能需要子类实现
abstract void getData();
abstract void calcData();
void printData(){
System.out.println(data);
}
}
//继承模板的具体模板对象
public class Template extends AbstractTemplate {
@Override
void getData() {
data = "data";
}
@Override
void calcData() {
data = (String)data+data;
}
}
public class TestUse {
public static void main(String args[]){
Template template = new Template();
template.dealData();
}
}
动机(Motivation)
模式定义
要点总结
代码示例
代码中,我们需要保存数据,但是使用哪种保存策略是变化的,如果使用if else结构来实现这种逻辑,显然是不合理的,如果添加一种新的保存策略,就需要添加新if else块。所以我们可以使用策略模式。我们还可以使用setSaveData来动态的修改保存策略,这里非常直观的将变化的部分提取出来,单独实现,从而减少耦合。通常来说如果在代码种出现if else结构,并且if无法枚举完所有情况或者枚举的情况太多,我们都可以考虑使用策略模式。
public class SaveClient {
private ISaveData saveData;
public SaveClient(ISaveData saveData){
this.saveData = saveData;
}
public void setSaveData(ISaveData saveData){
this.saveData = saveData;
}
public void save(Object data){
saveData.save(data);
}
}
public interface ISaveData {
void save(Object data);
}
public class SaveToFile implements ISaveData {
@Override
public void save(Object data) {
System.out.println("数据:" + data + " 保存到文件");
}
}
public class SaveToMysql implements ISaveData {
@Override
public void save(Object data) {
System.out.println("数据:" + data + " 保存到Mysql");
}
}
public class SaveToRedis implements ISaveData {
@Override
public void save(Object data) {
System.out.println("数据:" + data + " 保存到Redis");
}
}
public class TestUse {
public static void main(String args[]){
Object data = "数据";
ISaveData saveData = new SaveToRedis();
SaveClient client = new SaveClient(saveData);
client.save(data);
client.setSaveData(new SaveToFile());
client.save(data);
}
}
动机(Motivation)
模式定义
要点总结
代码示例
在代码中我们使用安卓和苹果订阅天气服务为示例,当天气变化的时候,安卓和苹果就会自动的打印出天气变化消息。
//观察者接口
public interface Client {
void getWeather(WeatherInfo info);
}
public class ClientAndroidServer implements Client {
private static String name = "安卓服务";
private WeatherInfo info;
@Override
public void getWeather(WeatherInfo info) {
this.info = info;
dealMsg();
}
private void dealMsg(){
System.out.println(name + "收到最新天气:time="+info.getTime()+"msg="+info.getWeather()+"。马上开始推送消息...");
}
}
public class ClientIphoneServer implements Client {
private static String name = "苹果服务";
private WeatherInfo info;
@Override
public void getWeather(WeatherInfo info) {
this.info = info;
dealMsg();
}
private void dealMsg(){
System.out.println(name + "收到最新天气:time="+info.getTime()+"msg="+info.getWeather()+"。马上开始推送消息...");
}
}
//主题接口
public interface IWeatherService {
void addClient(Client client); //添加观察者
boolean deleteClient(Client client);//删除观察者
void notifyClients(); //通知
void updateWeather(WeatherInfo info);//主题内容更新
}
//主题实现
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
//主题,同时使用了枚举实现单例
public enum WeatherService implements IWeatherService{
instance;
private LinkedList<WeatherInfo> weatherInfos = new LinkedList<WeatherInfo>();
private LinkedHashSet<Client> clients = new LinkedHashSet<Client>();//存放观察者
//添加观察者
@Override
public void addClient(Client client) {
clients.add(client);
}
//删除观察者
@Override
public boolean deleteClient(Client client) {
return clients.remove(client);
}
//通知观察者
@Override
public void notifyClients() {
Iterator<Client> iterator = clients.iterator();
while(iterator.hasNext()){
iterator.next().getWeather(weatherInfos.peekFirst());
}
}
//更新天气
@Override
public void updateWeather(WeatherInfo info) {
if(weatherInfos.size()>0)
if(weatherInfos.peekFirst().equals(info)) return;
weatherInfos.push(info);
if(clients.size()==0) return;
notifyClients();
}
}
//天气的消息实体
public class WeatherInfo {
private long time;
private String weather;
public WeatherInfo(long time,String weather){
this.time = time;
this.weather = weather;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public String getWeather() {
return weather;
}
public void setWeather(String weather) {
this.weather = weather;
}
@Override
public boolean equals(Object obj) {
WeatherInfo info = (WeatherInfo) obj;
return info.time==this.time&&info.weather.equals(this.weather);
}
}
public class TestUse {
public static void main(String args[]){
//创建主题
WeatherService service = WeatherService.instance;
//添加观察者
service.addClient(new ClientAndroidServer());
service.addClient(new ClientIphoneServer());
//更新主题
service.updateWeather(new WeatherInfo(System.currentTimeMillis(), "多云"));
service.updateWeather(new WeatherInfo(System.currentTimeMillis()+1000*60*60*24, "多云转晴"));
service.updateWeather(new WeatherInfo(System.currentTimeMillis()+1000*60*60*24*2, "晴"));
}
}
动机(Motivation)
模式定义
要点总结
代码示例
//被装饰者接口
public interface IPersistentUtil {
void persistentMsg(String msg);
}
//具体的被装饰者
public class PersistentUtil implements IPersistentUtil{
@Override
public void persistentMsg(String msg) {
System.out.println(msg + " 存入文件");
}
}
//装饰
public abstract class PersistentDecorator implements IPersistentUtil {
IPersistentUtil iPersistentUtil;
public PersistentDecorator(IPersistentUtil iPersistentUtil){
this.iPersistentUtil = iPersistentUtil;
}
@Override
public void persistentMsg(String msg) {
iPersistentUtil.persistentMsg(msg);
}
}
//装饰--存入数据库
public class PersistentDbDecorator extends PersistentDecorator {
public PersistentDbDecorator(IPersistentUtil iPersistentUtil){
super(iPersistentUtil);
}
@Override
public void persistentMsg(String msg) {
iPersistentUtil.persistentMsg(msg);
persistentToDb(msg);
}
private void persistentToDb(String msg){
System.out.println(msg + " 存入数据库");
}
}
//装饰--存入网络其他地方
public class PersistentNetDecorator extends PersistentDecorator {
public PersistentNetDecorator(IPersistentUtil iPersistentUtil){
super(iPersistentUtil);
}
@Override
public void persistentMsg(String msg) {
iPersistentUtil.persistentMsg(msg);
persistentToNet(msg);
}
private void persistentToNet(String msg){
System.out.println(msg + " 存入网络的其他地方");
}
}
public class TestUse {
public static void main(String args[]){
//被装饰者
final String data = "数据";
IPersistentUtil iPersistentUtil = new PersistentUtil();
iPersistentUtil.persistentMsg(data);
System.out.println("下面装饰数据库持久化:");
iPersistentUtil = new PersistentDbDecorator(iPersistentUtil);
iPersistentUtil.persistentMsg(data);
System.out.println("下面继续装饰网络存储器持久化:");
iPersistentUtil = new PersistentNetDecorator(iPersistentUtil);
iPersistentUtil.persistentMsg(data);
}
}
动机(Motivation)
模式定义
要点总结
代码示例
在代码中有两种存储方式(commonSave和massageSave)分别表示数据存储成功后给不给提示信息, 实现方式也有两种(SaveToDB 和SaveToFile)分别表示存储到数据库还是文件中。存储方式和实现方式是两种不同变化的维度,我们使其自由组合。
//抽象
public abstract class AbstractSave {
ISaveData saveData;
public AbstractSave(ISaveData saveData){
this.saveData = saveData;
}
public abstract void save(Object data);
}
//细化抽象
public class commonSave extends AbstractSave{
public LocalSave(ISaveData saveData) {
super(saveData);
}
@Override
public void save(Object data) {
System.out.print("本地存储:");
saveData.save(data);
}
}
//细化抽象
public class massageSave extends AbstractSave{
public NetSave(ISaveData saveData) {
super(saveData);
}
@Override
public void save(Object data) {
System.out.print("网络存储:");
saveData.save(data);
saveData.sendMassage();
}
}
//实现
public interface ISaveData {
void save(Object data);
void sendMassage();
}
//具体实现
public class SaveToDB implements ISaveData{
@Override
public void save(Object data) {
System.out.println(data + " 存储到数据库");
}
@Override
public void sendMassage(){
System.out.println("数据已被存储到数据库");
}
}
//具体实现
public class SaveToFile implements ISaveData{
@Override
public void save(Object data) {
System.out.println(data + " 存储到文件");
}
@Override
public void sendMassage(){
System.out.println("数据已被存储到文件");
}
}
public class TestUse {
public static void main(String args[]){
Object data = "数据";
ISaveData saveDataDb = new SaveToDB();
ISaveData saveDataFile = new SaveToFile();
AbstractSave save;
save = new commonSave(saveDataDb);
save.save(data);
save = new commonSave(saveDataFile);
save.save(data);
save = new massageSave(saveDataDb);
save.save(data);
save = new massageSave(saveDataFile);
save.save(data);
}
}
代码中第一个变化维度是CPU类型,第二个变化维度是不同品牌的电脑,最后可以自由组合
//实现者
interface Cpu{
String discribe();
}
//具体实现者*2
class Amd implements Cpu{
public String discribe() {
return "AMD CPU";
}
}
class Intel implements Cpu{
public String discribe() {
return "INTEL CPU";
}
}
//抽象
abstract class AbstractComputer{
Cpu cpu;
public AbstractComputer(Cpu cpu){
this.cpu=cpu;
}
public abstract void discribe();
}
//细化抽象*2
class LenevoComputer extends AbstractComputer{
public LenevoComputer(Cpu cpu) {
super(cpu);
}
@Override
public void discribe() {
System.out.println("联想笔记本cpu:"+super.cpu.discribe());
}
}
class HaseeComputer extends AbstractComputer{
public HaseeComputer(Cpu cpu) {
super(cpu);
}
@Override
public void discribe() {
System.out.println("神舟笔记本cpu:"+super.cpu.discribe());
}
}
//桥接模式
public class SimpleBridge {
public static void main(String args[]){
new LenevoComputer(new Amd()).discribe();
new HaseeComputer(new Intel()).discribe();
}
}
动机(Motivation)
模式定义
要点总结
代码中我们有两种不同的产品和对应的工厂,并且还有一个商店出售它们,关于商品出售什么,我们延迟到了主类中再确定。
//抽象产品
interface MeizuPhone{
String describe();
}
//具体产品*2
class PRO5 implements MeizuPhone{
@Override
public String describe() {
return "PRO5";
}
}
class MX5 implements MeizuPhone{
@Override
public String describe() {
return "MX5";
}
}
interface IFactory{
MeizuPhone produce();
}
class BigFactory implements IFactory{
@Override
public MeizuPhone produce() {
return new PRO5();
}
}
class SmallFactory implements IFactory{
@Override
public MeizuPhone produce() {
return new MX5();
}
}
class Store{
IFactory factory;
public Stroe(IFactory factory){
this.factory = factory;
}
public void sell(){
System.out.println("sell " + factory.produce().describe());
}
}
//工厂方法模式
public class FactoryMethod {
public static void main(String args[]){
Store store;
store = new Store(new SmallFactory());
store.sell();
store = new Store(new BigFactory());
store.sell();
}
}
动机(motivation)
模式定义
要点总结
代码示例
代码中EP21和MX5是同一个系列,EP30和PRO5是同一个系列,需要配套使用。
//抽象产品1
interface MeizuPhone{
void run();
}
class PRO5 implements MeizuPhone{
@Override
public void run() {
System.out.println("我是一台PRO5");
}
}
class MX5 implements MeizuPhone{
@Override
public void run() {
System.out.println("我是一台MX5");
}
}
//抽象产品2
interface Headset{
void play();
}
class EP21 implements Headset{
@Override
public void play() {
System.out.println("我是一副EP21和MX5配套使用");
}
}
class EP30 implements Headset{
@Override
public void play() {
System.out.println("我是一台EP30和PRO5配套使用");
}
}
//抽象工厂
interface IFactory{
MeizuPhone producePhone();
Headset produceHeadset();
}
//具体工厂
class BigFactory implements IFactory{
@Override
public MeizuPhone producePhone() {
return new PRO5();
}
@Override
public Headset produceHeadset() {
return new EP30();
}
}
//具体工厂
class SmallFactory implements IFactory{
@Override
public MeizuPhone producePhone() {
return new MX5();
}
@Override
public Headset produceHeadset() {
return new EP21();
}
}
//抽象工厂模式
public class AbstractFactory {
public static void main(String args[]){
IFactory bigfactory = new BigFactory();
IFactory smallfactory = new SmallFactory();
bigfactory.producePhone().run();
bigfactory.produceHeadset().play();
smallfactory.producePhone().run();
smallfactory.produceHeadset().play();
}
}
动机(motivation)
模式定义
要点总结
代码中我们使用了SimplePrototype作为一个可克隆自身的对象,在使用的时候我们给Client传入什么样的SimplePrototype(一般来说相对于直接new的状态是改变了一些属性的),在获取的时候就返回什么样的SimplePrototype,只是这个SimplePrototype是一个新的SimplePrototype。
//抽象原型
interface Prototype{
Object cloneSelf();//克隆自身的方法
}
//具体原型
public class SimplePrototype implements Prototype,Cloneable {
int value;
//这样的clone()实现只是示例,并不适合在实际工程中这样做,可以使用序列化和反序列化来实现
@Override
public Object cloneSelf() {
SimplePrototype self = new SimplePrototype();
self.value = value;
return self;
}
}
//客户端使用
class Client{
SimplePrototype prototype;
public Client(SimplePrototype prototype){
this.prototype = prototype;
}
public Object getPrototype(){
return prototype.cloneSelf();
}
}
Public class Prototype{
public static void main(){
SimplePrototype simplePrototype = new SimpePrototype();
simplePrototype.value = 500;
Client client = new Client(simplePrototype);
simplePrototype = (SimplePrototype)client.getPrototype();
System.out.println(simplePrototype.value);
}
}
动机(Motivation)
模式定义
要点总结
在代码中,我们有不同的生产器来生产出我们想要的产品。如果按照普通的思维,想要不同的产品就直接写一个类,然后直接new。但是这样产生的不同的类中生产步骤是一样的,也就是有一些结构的重复,我将这些不变的部分提取出来作为指挥者(Director),然后将不同的实现的具体方法也作为不同的类。最后原来一个可以直接new的类被分为需要生产的产品类,指挥者类,实现类。通过替换指挥者类中的实现类,就可以生产出不同的产品类。实际上构建器构建的是将产品从new的最初的状态构建为我们需要的状态。
//产品
public class MyDate {
String date;
}
//抽象生成器
public interface IDateBuilder {
MyDate myDate;
void buildDate(int y,int m,int d);
MyDate getData();
}
//具体生成器
public class DateBuilder1 implements IDateBuilder{
public DateBuilder1(MyDate myDate){
this.myDate = myDate;
}
@Override
public void buildDate(int y, int m, int d) {
myDate.date = y+"-"+m+"-"+d;
}
@Override
public MyDate getDate() {
return myDate;
}
}
//具体生成器
public class DateBuilder2 implements IDateBuilder{
public DateBuilder2(MyDate myDate){
this.myDate = myDate;
}
@Override
public void buildDate(int y, int m, int d) {
myDate.date = y+" "+m+" "+d;
}
@Override
public MyDate getDate() {
return myDate;
}
}
//指挥者
public class Derector {
private IDateBuilder builder;
public Derector(IDateBuilder builder){
this.builder = builder;
}
public Mydate buildDate(int y,int m,int d){
builder.buildDate(y, m, d);
return builder.getData();
}
}
public class TestUse {
public static void main(String args[]){
Derector derector;
MyDate mydate = new MyDate();
derector = new Detector(new DateBuilder1(mydate));
derector.buildDate(2066, 3, 5);
System.out.println(mydata.date);
MyDate mydate2 = new MyDate();
derector = new Detector(new DateBuilder2(mydate2));
derector.buildDate(2066, 3, 6);
System.out.println(mydata2.date);
}
}
动机(Motivation)
模式定义
要点总结
单例模式是一个非常著名的问题,网上的代码示例很多,这里就不给出代码示例了。可以参考https://mp.weixin.qq.com/s/OHVMyZJzKIjk3fA7FzDTvg