浅谈开发中常用的设计模式
设计模式在开发中占很重要的地位。在大型项目中使用好设计模式往往会取得事半功倍的效果。本篇博客就介绍下几种在开发中常用到的设计模式。
设计原则
先看下一些约定俗成的设计原则,其实要遵守以下所有原则很难,但开发过程中还是要有这样的意识。
- 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。(封装变化)
- 针对接口编程,而不是针对实现编程。
- 多用组合,少用继承:用组合建立的系统具有很大的弹性,不仅可以将算法封装成类,也可以在运行时动态地改变行为。总结一句话就是,有一个比是一个更好。
- 为交互对象之间的松耦合设计而努力。
- 对扩展开放,对修改关闭。(装饰者是很好的体现)
- 要依赖抽象,不要依赖具体类。这就是依赖倒置原则。它更强调的是抽象,不能让高层组件依赖低层组件。
- 最少知识原则:只和你的密友谈话。就是说当你在设计一个系统,不管任何对象,你都要注意它所交互的类有哪些。不要让太多的类藕合在一起。
- 单一模式:一个类应该只有一个引起变化的原因。
模式介绍
策略模式
策略模式定义是:定义算法族,分别封装起来,让它们之间可以互相替换,算法的变化独立于使用算法的客户。
我们来模拟一种情形来理解这句话。有一群鸭子,有各种颜色的鸭,他们有的会飞,有的不会飞,飞的姿态也更不相同。此时如果在每只鸭子里分别定义飞的姿态,那有成千上万中鸭子的时候就会累死。这时我们考虑使用设计模式来实现下它。
设计原则中第一条:找出应用中可能需要变化之处,把它们独立出来。当然这里我们独立的就是会变化的飞行为。
设计模式第二条:针对接口编程,而不是针对实现编程。所以到这里我们写出如下飞的代码:
public interface FlyBehavior {public void fly();
}
定义了接口类,再定义实现类,会简单,只定义会飞和不会飞行为:
public class NoFly implements FlyBehavior {@Overridepublic void fly() {// TODO Auto-generated method stubSystem.out.println("this duck can not fly");}}
public class CanFly implements FlyBehavior{@Overridepublic void fly() {// TODO Auto-generated method stubSystem.out.println("this duck can fly");}}
以上就是针对接口编程,那它有什么好处呢,继续往下看。
设计原则第三条:多用组合,少用继承。那我们也来运用下。定义鸭子的抽象类:
public abstract class Duck {FlyBehavior flyBehavior;public abstract void disply();public void performFly(){flyBehavior.fly();}public FlyBehavior getFlyBehavior() {return flyBehavior;}public void setFlyBehavior(FlyBehavior flyBehavior) {this.flyBehavior = flyBehavior;}}
其中它有一个FlyBehavior对象,组合了飞的行为,典型的“有一个“而不是”有一个“。
好了,接下来就是实体鸭子, 只要继承超类就可以了。
public class RedDuck extends Duck{public RedDuck() {// TODO Auto-generated constructor stubflyBehavior = new NoFly();//默认不会飞}@Overridepublic void disply() {// TODO Auto-generated method stubSystem.out.println("the color is red");}}
红鸭不会飞,再来一只黑鸭会飞:
public class BlackDuck extends Duck{public BlackDuck() {// TODO Auto-generated constructor stubflyBehavior = new CanFly();//默认不会飞}@Overridepublic void disply() {// TODO Auto-generated method stubSystem.out.println("the color is black");}
}
最后我们来调用一下:
public class Main {public static void main(String[] args){Duck duck = new RedDuck();duck.performFly();duck.disply();duck.setFlyBehavior(new CanFly());duck.performFly();System.out.println("-----------------");Duck duck2 = new BlackDuck();duck2.performFly();duck2.disply();duck2.setFlyBehavior(new NoFly());duck2.performFly();}
}
这就是大名鼎鼎的策略模式。好处己经非常明显了,要什么飞行行为只要在运行时进行替换就可以了。这种模式的好处:实现不会被绑死在子类中,使用接口,可以运行时替换。看上它的UML图:
观察者模式
定义了对象之间的一对多依赖,这样一来,当一个对象改变时,它的所有依赖者都会收到通知并自动更新。
模拟场景的话很简单,就是比如图书馆,你在图书馆借书,相当于你就是图书馆的一个观察者,当图书馆有新闻发布时你就会收到通知。
先看一下它的UML图:
从观察人员入手:
public interface Observer {public void update(String name);public void disConnect();
}
只需要两个方法,有消息更新后会通知你(update)。如果你觉得烦也可以取消观察。新建实现类小明:
public class XiaoMingObserver implements Observer{String bookName;private Subject subject;public XiaoMingObserver(Subject subject) {// TODO Auto-generated constructor stubthis.subject = subject;subject.registerObserver(this);}@Overridepublic void update(String name) {// TODO Auto-generated method stubSystem.out.println ("i am xiaoMing,the new book is "+name);}@Overridepublic void disConnect() {// TODO Auto-generated method stubthis.subject.removeObserver(this);}
}
小明拥有图书证(有一个Subject 对象),subject注册了它,它就成了一个观察者,看下subject:
public interface Subject {public void registerObserver(Observer o);public void removeObserver(Observer o);public void notifyObservers();
}
实现三个功能,注册观察者,删除观察者,通知变化。可见它要拥有观察者对象。看下具体的实现。
public class BookSubject implements Subject {private String bookName;ArrayList<Observer> aList; public BookSubject() {// TODO Auto-generated constructor stubaList = new ArrayList<Observer>();}@Overridepublic void registerObserver(Observer o) {// TODO Auto-generated method stubaList.add(o);}@Overridepublic void removeObserver(Observer o) {// TODO Auto-generated method stubif(aList.contains(o)){aList.remove(o);}}@Overridepublic void notifyObservers() {for(Observer observer :aList){if(observer instanceof XiaoGaoObserver){bookName = "java编程思想";}else{bookName = "c++编程思想";}observer.update(bookName);}}
}
registerObserver添加观察者到List中。发布通知也就是调用观察者的Notify方法。观察者在android源码中就很我地方体现,如Adapter中就是观察数据变化就更改界面。以后有时间写下Adapter的源码分析。
工厂模式
工厂模式有三种,个人感觉工厂模式还是比较复杂的。一步步讲吧,最后会把源码附上。
1.简单工厂模式
简单工厂模式最好理解,平时用得也很多。简单工厂模式主要是在初始化对象进行解耦合,工厂模式封装了创建对象的细节。一般是静态方法。但使用静态方法有一个缺点,就是无法通过继承来改变对象创建过程。
我们来模拟一个场景,假设我们在卖肠粉(最爱肠粉了。。。)。我们要做很多口味,这时不能做一种口味就new一个肠粉,因为做肠粉只有前面加料时步骤不一样,后面的切跟蒸都是一样的。先看上UML图:
所以我们用简单工厂模式写出以下代码:
public class SimpleChangfenStore {SimpleFactory mFactory = null;public SimpleChangfenStore(SimpleFactory factory){this.mFactory = factory;}public void orderChangfen(String tag){Changfen mChangfen = null;mChangfen = mFactory.createChangfen(tag);mChangfen.prepare();mChangfen.bake();mChangfen.cut();System.out.println("------finish one-------");}
}
createChangfen的作用就是用于抽取出来专门创建肠粉对象,这样做的好处是可以防止你每次添加一种口味的肠粉都要修改这个类。看下它的代码:
public class SimpleFactory {public Changfen createChangfen(String tag){ Changfen changfen = null;if(tag.equals("vegetable")){changfen = new VegetableChangfen();}else if(tag.equals("meat")){changfen = new MeatChangfen();}return changfen;}
}
根据tag创建不同的肠粉。最后来看下如何使用:
public class SimpleMain {public static void main(String[] args){SimpleFactory factory = new SimpleFactory();SimpleChangfenStore store = new SimpleChangfenStore(factory);store.orderChangfen("meat");store.orderChangfen("vegetable");}
}
很简单,只要知道factory专门用来创建对象的就可以了。看下输出结果:
接下来看下工厂模式。
工厂模式
工厂模式:把创建changfen分为子类中,定义一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。
其实也很好理解,先看下UML图:
回到我们的肠粉店,现在我们的生意很好,要开分店啦,很开心。在深圳和汕头更来一家店。那深圳和汕头创建的店对象肯定是不同的嘛。所以类的实例化在到子类中,让子类自己来创建。为此,我们的店要把创建对象的方法定义成抽象的。
public abstract class ChangfenStore {public abstract Changfen createChangfen(String tag);public void orderChangfen(String tag){Changfen mChangfen = null;mChangfen = createChangfen(tag);mChangfen.prepare();mChangfen.bake();mChangfen.cut();System.out.println("------finish one-------");}
}
createChangfen定义成抽象的了,要由子类来实现,看下深圳的子类:
public class SZStore extends ChangfenStore{@Overridepublic Changfen createChangfen(String tag) {// TODO Auto-generated method stubChangfen changfen = null;if(tag.equals("vegetable")){changfen = new SZVegetableChangfen();}else if(tag.equals("meat")){changfen = new SZMeatChangfen();}return changfen;}}
看吧,深圳用的是深圳的肉和菜,小看一眼:
public class SZVegetableChangfen extends Changfen{@Overridepublic void prepare() {// TODO Auto-generated method stubSystem.out.println("i am in Shenzhen,i like the cabbage,so i add the cabbage");}}
这样就实现了工厂模式。看下如何使用:
public class Main {public static void main(String[] args){ChangfenStore SZstore = new SZStore();SZstore.orderChangfen("meat");SZstore.orderChangfen("vegetable");ChangfenStore STstore = new STStore();STstore.orderChangfen("meat");STstore.orderChangfen("vegetable");}
}
输出如下:
好啦 ,接下来讲讲抽象工厂方法啦。
抽象工厂方法
抽象工厂模式:提供一个接口,用于创建或依赖对象的家族,而不需要明确指定具体类。它提供了一个原料的生产工厂,原料的生产对客户不可见。
不太好理解,其实就是创建一些依赖对象的原料。继续看我们的肠粉。我们深圳店和汕头店加的原料肯定是不同的,即使是用鱼,那鱼的种类也不一定相同。用一句话说就是深圳店和汕头店要有自己的原料工厂。
原料嘛,就要有原料工厂,先看下原料工厂:
public abstract class AbstractChangfenFactory {public abstract Flour createFlour();public abstract Sauce createSauce();public abstract Seasoning createseasoning();}
它是一个抽象类。肠粉要加酱加料等。具体加哪些酱哪些料,看具体实现类:
public class SZChangfenFactory extends AbstractChangfenFactory{@Overridepublic Flour createFlour() {// TODO Auto-generated method stubreturn new SZFlour();}@Overridepublic Sauce createSauce() {// TODO Auto-generated method stubreturn new SZSauce();}@Overridepublic Seasoning createseasoning() {// TODO Auto-generated method stubreturn new SZSessioning();}
}
看吧,是深圳特有的SZSauce,SZFlour等。这些都是对象,本例子只是简单的打印一句话,这里就不贴出来了,具体就不贴出来了。要记得汕头也有自己的原料STSauce等。
原料都买好了,开始做肠粉吧:
public abstract class AbstractChangfen{protected Sauce mSauce = null;protected Flour mFlour = null;protected Seasoning mSeasioning = null;public abstract void prepare();public void bake(){System.out.println("after prepare,the Changfen should be bake");}public void cut(){System.out.println("after bake,the Changfen should be cut");}
}
看下深圳是怎么做的,来到深圳分店视察:
public class STStore extends ChangfenStore{@Overridepublic AbstractChangfen createChangfen(String tag) {AbstractChangfen changfen = null;AbstractChangfenFactory factory;factory = new STChangfenFactory();if(tag.equals("vegetable")){changfen = new STAbstractVegetableChangfen(factory);}else if(tag.equals("meat")){changfen = new STAbstractMeatChangfen(factory);}return changfen;}}
深圳人嘛,要记得选择深圳的原料工厂哦。选其中的做肉肠粉的代码来看一看:
public class STAbstractMeatChangfen extends AbstractChangfen{private AbstractChangfenFactory mFactory = null;public STAbstractMeatChangfen(AbstractChangfenFactory factory) {// TODO Auto-generated constructor stubthis.mFactory = factory;}@Overridepublic void prepare() {// TODO Auto-generated method stubthis.mSauce = this.mFactory.createSauce();this.mFlour = this.mFactory.createFlour();System.out.println("i am in ShanTou factory,i like meat,the sause is "+this.mSauce.print()+",the flour is "+this.mFlour.print());}}
到此就一目了然了,深圳用深圳的原料,汕头用汕头的原料。输出结果如下:
到此工厂模式就讲完了。看下UML图。画得比较复杂,细心看,能看懂的。
篇幅关系,还有几个常用设计模式下篇再总结。先到这吧。
浅谈开发中常用的设计模式相关推荐
- Java开发中常用的设计模式-单例模式
单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式. Java开发中常用的设计模式-单例模式 单例模式有3个特点: 单例类只有一个实例对象: 该单例对象必须 ...
- 浅谈开发中的MVVM模式及与MVP和MVC的区别
2019独角兽企业重金招聘Python工程师标准>>> 我记得前段时间分享了一篇文章< 浅谈Andorid开发中的MVP模式>(点击可跳转),反响不错,为了进一步介绍MV ...
- 游戏开发中常用的设计模式 【game design patterns】
单例模式(Singleton Pattern):用于确保在游戏中只存在一个实例,例如游戏管理器(Game Manager)或资源管理器(Resource Manager). 工厂模式(Factory ...
- 游戏引擎开发中常用的设计模式
仅仅因为你知道编程语言的语法,不足以让你成为一个程序员.我讨厌这么对你说,但它确实是真的.什么知识将会使你成为一个真正的程序员呢?答案是数据结构,算法和设计模式的知识.语言的语法与知道字母表同义.任何 ...
- 游戏开发中常用的设计模式
使用设计模式来提高程序库的重复利用性是大型程序项目开发必须的.但是在"四人帮"的设计模式概述中提到了23种标准设计模式,不但难以记住,而且有些设计模式更多的适用于应用程序开发,对游 ...
- 浅谈UML中常用的几种图——鲁棒图
什么是鲁棒图 鲁棒图包含 3 种元素(如图 8-2 所示),它们分别是边界对象.控制对象.实体对象: 边界对象对模拟外部环境和未来系统之间的交互进行建模.边界对象负责接收外部输入,处理内部内容的解释, ...
- 前端开发中常用设计模式-总结篇
本文是向大家介绍前端开发中常用的设计模式,它使我们编写的代码更容易被复用,也更容易被人理解,并且保证代码的稳定可靠性. 1.什么是设计模式 通俗来讲,就是日常使用设计的一种惯性思维. 因为对应的这种思 ...
- 浅谈实际开发中常用的分布式事物处理
浅谈实际开发中常用的分布式事物处理 文章目录 前言 一.分布式事物 二.常用方案 1.使用记录表+mq机制 前言 随着微服务的流行,越来越多系统不在是单体结构,根据业务和功能拆分成不同微服务,这就导致 ...
- 理解各种设计模式原则及区别丨浅谈Nginx中核心设计模式-责任链模式丨C++后端开发丨Linux服务器开发丨web服务器
理解各种设计模式原则及区别丨浅谈Nginx中核心设计模式-责任链模式 1. 开闭.单一职责.里氏替换.接口隔离等设计原则 2. 随处可见的模板方法 3. nginx中核心设计模式 责任链模式 4. 责 ...
最新文章
- 通用权限管理系统组件 (GPM - General Permissions Manager)
- linux c 实现函数 trim 除去字符串首尾空格
- Java第四次作业——面向对象高级特性(继承和多态)
- C# 三层级架构问题之 能加载文件或程序集或它的某一个依赖项。系统找不到指定的文件
- haroopad夜间模式与数学公式显示
- P3338 [ZJOI2014]力 FFT + 推式子
- 互联网晚报 | 4月08日 星期五 | 国家网信办:互联网企业近半年来用工人数保持平稳;特斯拉将推出一款“专用的”自动驾驶出租车...
- 数据类型的基本表达式
- opencv学习之路(9)、对比度亮度调整与通道分离
- 【bzoj2199/Usaco2011 Jan】奶牛议会——2-sat
- Windows Server已可安装Docker,Azure开始支持Mesosphere
- Linux命令基础5-文件重定向
- 高级语言程序设计(C语言) 笔记整理
- STM32开发 | 移远4G-Cat.1模组EC200N-CN开发
- 12306 崩了,90% 的人都用过这三款抢票工具
- HDUOJ 1069 Monkey and Banana
- 爱心~~~红色的~~~小爱心组成的大爱心~~~
- FX5U 原点回归指令 DSZR
- Excel中 VLOOKUP 函数的使用
- 华为云区块链服务技术决策和落地实践