设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使代码编写真正工程化,设计模式是软件工程的基石,如同大厦的设计图一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。
一、设计模式的六大原则
1、开闭原则(Open Close Principle)
开闭原则就是说:对扩展开放,对修改关闭。在程序需要进行扩展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、依赖倒转原则(Dependence Inversion Principle)
依赖倒转原则就是说:针对接口编程,依赖于抽象而不依赖于具体。它是开闭原则的基础。
3、里氏代换原则(Liskov Substitution Principle)
里氏代换原则就是说:任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
4、接口隔离原则(Interface Segregation Principle)
接口隔离原则就是说:使用多个隔离的接口,比使用单个接口要好。其实也就是降低类之间的耦合度的意思。
5、合成复用原则(Composite Reuse Principle)
合成复用原则就是说:尽量使用合成/聚合的方式,而不是使用继承。
6、迪米特原则(最少知道原则)(Demeter Principle)
迪米特原则就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
二、设计模式的分类与应用
总体来说设计模式分为三大类(23种):
3、行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
1、策略模式:定义一系列算法类,将每一个算法封装成一个类,并让它们可以相互替换使用,主要目的是将算法定义与使用分开。此模式由2部分组成:
①抽象策略类:
public interface Calculator {
public String calculate(String str);
}
②具体策略类1:
public class Calculator1 implements Calculator {
public String calculate(String str) {
return "第一个算法:str="+str;
}
}
具体策略类2:
public class Calculator2 implements Calculator {
public String calculate(String str) {
return "第二个算法:str="+str;
}
}
具体策略类3:
public class Calculator3 implements Calculator {
public String calculate(String str) {
return "第三个算法:str="+str;
}
}
主入口:
public class Test {
public static void main(String[] args) {
Calculator cal1 = new Calculator1();
Calculator cal2 = new Calculator2();
Calculator cal3 = new Calculator3();
System.out.println(cal1.calculate("123"));
System.out.println(cal2.calculate("456"));
System.out.println(cal3.calculate("789"));
}
}
2、模板方法模式:某流程有多个步骤(方法),其中有某几步是固定的,而某几步是可变化的。这时就需要一个抽象类,将这些固定的步骤(方法)放在抽象类中,而有变化的步骤只在抽象类中定义而不作具体的实现。具体的实现在抽象类的子类中实现。此模式由2部分组成:
①抽象类:定义由若干操作组成的模板,这些操作可以是抽象的,也可以是具体的,在子类中可以重写这些操作。
public abstract class AbstractStep {
public void execute(){
step1();
step2();
step3();
}
public void step1(){
System.out.println("第一步");
}
public abstract void step2();
public void step3(){
System.out.println("第三步");
}
}
②具体子类1:
public class StepOfType1 extends AbstractStep {
public void step2() {
System.out.println("类型1的流程中的第二步");
}
}
具体子类2:
public class StepOfType2 extends AbstractStep {
public void step2() {
System.out.println("类型2的流程中的第二步");
}
}
主入口:
public class Test {
public static void main(String[] args) {
AbstractStep process1 = new StepOfType1();
process1.execute();
AbstractStep process2 = new StepOfType2();
process2.execute();
}
}
3、观察者模式:某一对象状态或行为的变化会引起其他某一对象或多个对象状态或行为的变化,此模式用于建立对象与对象之间的依赖关系。此模式由4部分组成:
①观察者接口: 观察者将因目标的变化而做出反应。
public interface Observer {
public void action();
}
②观察者1实现:
public class Observer1 implements Observer {
public void action() {
System.out.println("观察者1开始行动");
}
}
观察者2实现:
public class Observer2 implements Observer {
public void action() {
System.out.println("观察者2开始行动");
}
}
③目标抽象类:定义一个观察者集合,提供增加和删除观察者的方法,同时定义通知观察者的方法。
import java.util.ArrayList;
public abstract class AbstractTarget{
public ArrayList<Observer> observers = new ArrayList<Observer>();
public void add(Observer observer) {
this.observers.add(observer);
}
public void del(Observer observer) {
this.observers.remove(observer);
}
public abstract void notifyObserver();
}
④目标子类:
public class Target extends AbstractTarget {
public void notifyObserver() {
for(Object obs:observers) {
((Observer)obs).action();
}
}
}
主入口:
public class Test {
public static void main(String args[]){
Observer1 observer1= new Observer1();
Observer2 observer2= new Observer2();
AbstractTarget target = new Target();
target.add(observer1);
target.add(observer2);
target.notifyObserver();
}
}
4、迭代器模式:对含有多个元素的聚合类对象进行访问或遍历时,为避免聚合类过于庞大,将遍历行为抽出来封装于迭代器中由迭代器提供遍历方法。此模式由4部分组成:
①聚合类接口:包含创建迭代器对象的方法。
import java.util.ArrayList;
import java.util.List;
public interface Aggregate {
public List list = new ArrayList();
public Iterator createIterator();
public void add(String str);
public void del(int n);
public Object get(int n);
}
②聚合类实现:包含创建迭代器对象的具体实现。
public class CollectAggregate implements Aggregate {
public Iterator createIterator() {
return new CollectIterator(this);
}
public void add(String str) {
list.add(str);
}
public void del(int n) {
list.remove(n);
}
public Object get(int n){
return list.get(n);
}
}
③迭代器接口:定义了访问和遍历聚合元素的方法。
public interface Iterator {
public Object firstItem();
public Object lastItem();
public boolean hasNextItem();
public Object nextItem();
public Object currentItem();
}
④迭代器实现:定义了访问和遍历聚合元素的方法的具体实现。
public class CollectIterator implements Iterator{
public Aggregate objects;
public int cursor=0;
public CollectIterator(Aggregate objects) {
this.objects=objects;
}
public Object firstItem(){
return objects.list.get(0);
}
public Object lastItem(){
int len = objects.list.size();
return objects.list.get(len-1);
}
public boolean hasNextItem(){
int n = this.cursor+1;
if(objects!=null && objects.list.size()>=n+1)
return true;
else
return false;
}
public Object nextItem(){
int n = this.cursor+1;
return objects.list.get(n);
}
public Object currentItem() {
return objects.list.get(this.cursor);
}
}
主入口:
public class Test {
public static void main(String args[]){
Aggregate agg = new CollectAggregate();
agg.add("a");
agg.add("b");
agg.add("c");
CollectIterator iterator = new CollectIterator(agg);
System.out.println(iterator.currentItem());
System.out.println(iterator.firstItem());
System.out.println(iterator.lastItem());
System.out.println(iterator.hasNextItem());
System.out.println(iterator.nextItem());
agg.del(1);
agg.del(1);
System.out.println(iterator.hasNextItem());
}
}
5、责任链模式:请求的处理者有多个,并且处理者优先级有一定的规律。比如直线型(如审批流程),环型(如打扑克)或树型等。此模式由2部分组成:
①抽象处理类:定义了请求处理的抽象方法以及请求到下一步时处理的抽象处理类的对象。
public abstract class AbstractHandler {
protected AbstractHandler nextHandler;
protected String handleName;
public AbstractHandler(String handleName){
this.handleName=handleName;
}
public void setNextHandler(AbstractHandler handler){
this.nextHandler=handler;
}
public abstract void handle(String request);
}
②具体处理类:实现了处理请求的抽象方法,在处理请求之前需要判断是否有权限处理该请求,如果无权限则将任务转到下一步。
处理者1:
public class Handler1 extends AbstractHandler {
public Handler1(String handleName) {
super(handleName);
}
public void handle(String request) {
if("ok1".equals(request)){
System.out.println(request+"已被"+this.handleName+"处理");
}else{
this.nextHandler.handle(request);
}
}
}
处理者2:
public class Handler2 extends AbstractHandler {
public Handler2(String handleName) {
super(handleName);
}
public void handle(String request) {
if("ok2".equals(request)){
System.out.println(request+"已被"+this.handleName+"处理");
}else{
this.nextHandler.handle(request);
}
}
}
处理者3:
public class Handler3 extends AbstractHandler {
public Handler3(String handleName) {
super(handleName);
}
public void handle(String request) {
if("ok3".equals(request)){
System.out.println(request+"已被"+this.handleName+"处理");
}else{
this.nextHandler.handle(request);
}
}
}
处理者4:
public class Handler4 extends AbstractHandler {
public Handler4(String handleName) {
super(handleName);
}
public void handle(String request) {
if("ok4".equals(request)){
System.out.println(request+"已被"+this.handleName+"处理");
}else{
System.out.println(request+"未到找相关规定,特批通道");
}
}
}
主入口:
public class Test {
public static void main(String args[]){
String request1 = "ok1";
String request2 = "ok2";
String request3 = "ok3";
String request4 = "ok4";
String request5 = "ok5";
AbstractHandler handler1 = new Handler1("项目经理");
AbstractHandler handler2 = new Handler2("部门经理");
AbstractHandler handler3 = new Handler3("大区经理");
AbstractHandler handler4 = new Handler4("总裁");
handler1.setNextHandler(handler2);
handler2.setNextHandler(handler3);
handler3.setNextHandler(handler4);
handler1.handle(request1);
handler1.handle(request2);
handler1.handle(request3);
handler1.handle(request4);
handler1.handle(request5);
}
}
6、命令模式:将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化。此模式将请求发送者和接收者完全解耦,使发送者与接收者之间没有直接引用关系。此模式由4部分组成:
①调用者类:即请求发送者,它通过命令对象来处理请求。
public class Invoker {
private AbstractCommand command;
public Invoker(AbstractCommand command) {
this.command = command;
}
public void setCommand(AbstractCommand command) {
this.command = command;
}
public void call() {
command.handleRequest();
}
}
②抽象命令类:一般是抽象类或接口,声明了可以调用接收者的相关方法。
public abstract class AbstractCommand {
public abstract void handleRequest();
}
③具体命令类:定义可以调用接收者的具体方法,一般会持有接收者类的对象。
具体命令类1:
public class Command1 extends AbstractCommand {
private Receiver1 receiver;
public Command1(){
receiver = new Receiver1();
}
public void handleRequest() {
receiver.disPatch();
}
}
具体命令类2:
public class Command2 extends AbstractCommand {
private Receiver2 receiver;
public Command2(){
receiver = new Receiver2();
}
public void handleRequest() {
receiver.redirect();
}
}
④接收者类:即请求处理类,处理由命令类传来的请求。与具体命令类一一对应。
接收者类1:
public class Receiver1 {
public void disPatch(){
System.out.println("request请求的第一种处理方法");
}
}
接收者类2:
public class Receiver2 {
public void redirect(){
System.out.println("request请求的第二种处理方法");
}
}
主入口:
public class Test {
public static void main(String[] args) {
AbstractCommand com1 = new Command1();
Invoker invoker = new Invoker(com1);
invoker.call();
AbstractCommand com2 = new Command2();
invoker.setCommand(com2);
invoker.call();
}
}
7、备忘录模式:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。用于实现后悔时的“反悔药”,比如在下棋中的悔棋功能,在计算机术语中,称之为“撤消”(Undo)。此模式由3部分组成:
①原发器类:即需要备份的类,一般都包含功能:创建备忘录、备份状态和还原状态。
public class Originator {
private String name;
private String state;
public Originator(String name,String state){
this.name=name;
this.state=state;
}
public Memento getMemento(){
return new Memento();
}
public Memento backupState(){
Memento memento = getMemento();
memento.setState(this.state);
System.out.println("name:"+this.name+",state:"+this.state+",已备份");
return memento;
}
public void restoreState(Memento memento){
this.state = memento.getState();
System.out.println("name:"+this.name+"状态已恢复成:"+this.state);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
②备忘录类:提供与原发器相对应的属性(可以是全部,也可以是部分),用于存储原发器的状态。为了只让原发器类控制备忘录类,所以将备忘录类定义为包级别,与原发器类放在同目录下。
class Memento {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
③管理者类:用于对备忘录的管理,主要负责添加备忘录。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Manager {
private List<Memento> mementoList = new ArrayList<Memento>();
public void addMemento(Memento memento){
mementoList.add(memento);
}
public Memento getMemento(){
return mementoList.get(mementoList.size()-1);
}
public Memento getMemento(int i){
return mementoList.get(i);
}
public void queryStates(){
System.out.print("备份的内容有:");
for(Iterator<Memento> iterator = this.mementoList.iterator();iterator.hasNext();){
System.out.print(iterator.next().getState()+",");
}
System.out.println();
}
}
主入口:
public class Test{
public static void main(String args[]){
Originator originator = new Originator("玩家1","取牌");
Manager manager = new Manager();
manager.addMemento(originator.backupState());
manager.queryStates();
originator.setState("碰");
manager.addMemento(originator.backupState());
manager.queryStates();
originator.setState("杠");
manager.addMemento(originator.backupState());
manager.queryStates();
originator.restoreState(manager.getMemento(1));
System.out.println("当前状态是:"+originator.getState());
originator.setState("吃");
manager.addMemento(originator.backupState());
manager.queryStates();
originator.setState("胡");
manager.addMemento(originator.backupState());
manager.queryStates();
System.out.println("当前状态是:"+originator.getState());
originator.restoreState(manager.getMemento());
}
}
8、状态模式:将对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化。此模式由3部分组成:
①抽象状态类:含有状态对应的行为声明,如果每种状态的行为都有公共的行为,可以将该公共方法抽出来放在抽象状态类中。
public abstract class AbstractState {
public void commonHandle(){
System.out.println("这是公共处理方法");
}
public abstract void handle();
}
②具体状态类:每种状态对应的行为的具体实现,每种状态对应一种具体的状态类。
具体状态类1:
public class State1 extends AbstractState {
public void handle() {
System.out.println("状态1的处理方法");
}
}
具体状态类2:
public class State2 extends AbstractState {
public void handle() {
System.out.println("状态2的处理方法");
}
}
具体状态类3:
public class State3 extends AbstractState {
public void handle() {
System.out.println("状态3的处理方法");
}
}
③环境类:持有抽象状态类对象和标识状态的值,根据值不同,将抽象状态类的对象转化为具体状态类的对象。
public class Context {
private AbstractState state;
private int value;
public void setState(AbstractState state){
this.state=state;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public void action(){
state.commonHandle();
state.handle();
}
public void changeState(){
if(value==1){
this.setState(new State1());
}
else if(value==2){
this.setState(new State2());
}
else{
this.setState(new State3());
}
}
}
主入口:
public class Test {
public static void main(String[] args) {
Context context = new Context();
context.setValue(1);
context.changeState();
context.action();
context.setValue(2);
context.changeState();
context.action();
context.setValue(3);
context.changeState();
context.action();
}
}
也可以将根据状态值注入状态类对象的方法放入状态类中,但需要以环境类对象为输入参数:
public void changeState(Context context){
if(context.getValue()==1){
context.setState(new State1());
}
else if(context.getValue()==2){
context.setState(new State2());
}
else{
context.setState(new State3());
}
}
9、访问者模式:用于对某结构对象中元素进行访问等操作,可以在不改变各元素类的前提下定义作用于这些元素的新的访问者的操作。此模式由5部分组成:
①抽象访问者类:为结构对象中的元素提供抽象访问方法,每种具体的元素类对应一个抽象的访问方法,具体元素类的对象作为方法的输入参数。
public abstract class Visitor {
public abstract void visitEmotionBlog(EmotionBlog blog);
public abstract void visitTechnologyBlog(TechnologyBlog blog);
}
②具体访问者类:为结构对象中的元素提供具体访问方法的实现,需要对抽象访问者类中的方法定义具体的方法实现。
具体访问者类1:
public class WapVisitor extends Visitor {
public void visitEmotionBlog(EmotionBlog blog){
System.out.println("手机访问博客"+blog.getBlogName());
}
public void visitTechnologyBlog(TechnologyBlog blog){
System.out.println("手机访问博客"+blog.getBlogName());
}
}
具体访问者类2:
public class WebVisitor extends Visitor {
public void visitEmotionBlog(EmotionBlog blog){
System.out.println("电脑访问博客"+blog.getBlogName());
}
public void visitTechnologyBlog(TechnologyBlog blog){
System.out.println("电脑访问博客"+blog.getBlogName());
}
}
③抽象元素类:是被访问对象的抽象接口,定义了被访问者类对象被访问的方法,访问者类对象作为方法的输入参数。
public abstract class Blog{
public String blogName;
public String getBlogName() {
return blogName;
}
public void setBlogName(String blogName) {
this.blogName = blogName;
}
public abstract void accept(Visitor visitor);
}
④具体元素类:是具体的被访问对象,对具体元素被访问的方法定义了具体的方法实现。
具体元素类1:
public class EmotionBlog extends Blog{
public EmotionBlog(String blogName){
this.blogName=blogName;
}
public void accept(Visitor visitor) {
visitor.visitEmotionBlog(this);
}
}
具体元素类2:
public class TechnologyBlog extends Blog{
public TechnologyBlog(String blogName){
this.blogName=blogName;
}
public void accept(Visitor visitor) {
visitor.visitTechnologyBlog(this);
}
}
⑤结构对象类:是访问者模式中最重要的部分,可以迭代访问它所持有的所有元素。
public class Blogs {
private List<Blog> blogs = new ArrayList<Blog>();
public void writeBlog(Blog blog) {
blogs.add(blog);
}
public void eraseBlog(Blog blog) {
blogs.remove(blog);
}
public void acceptVisit(Visitor visitor) {
for(Blog tmp : blogs) {
tmp.accept(visitor);
}
}
}
主入口:
public class Test {
public static void main(String[] args) {
Blogs blogs = new Blogs();
Blog blog1 = new EmotionBlog("情感博客");
Blog blog2 = new TechnologyBlog("技术博客");
blogs.writeBlog(blog1);
blogs.writeBlog(blog2);
Visitor visitor1 = new WapVisitor();
Visitor visitor2 = new WebVisitor();
blogs.acceptVisit(visitor1);
blogs.acceptVisit(visitor2);
}
}
10、中介者模式:用一个中介对象来封装一系列的对象交互,使各对象不需要显式地相互引用。此模式由4部分组成:
①抽象中介者类:用于定义中介者类与同事类之间通信的抽象方法,持有抽象同事类的集合并可以对该集合的元素进行增删操作。
public abstract class AbstractMediator {
protected List<AbstractColleague> colleagues=new ArrayList<AbstractColleague>();
public void register(AbstractColleague colleague) {
colleagues.add(colleague);
}
public abstract void callColleague(int i);
}
②具体中介者类:实现抽象中介者类中的抽象方法。
public class Mediator extends AbstractMediator{
public void callColleague(int i){
((AbstractColleague)(colleagues.get(i))).operation();
}
}
③抽象同事类:每个抽象同事类都持有抽象中介者类的对象,用于与中介者通信。同时定义了自身的抽象方法以及与其他同事类通信的方法。
public abstract class AbstractColleague {
protected AbstractMediator mediator;
public AbstractColleague(AbstractMediator mediator) {
this.mediator=mediator;
}
public abstract void operation(); //自身的行为
public void callColleague(int i) { //与其他同事类通信
mediator.callColleague(i);
}
}
④具体同事类:实现抽象同事类中的抽象方法。
具体同事类1:
public class Colleague1 extends AbstractColleague {
public Colleague1(AbstractMediator mediator) {
super(mediator);
}
public void operation(){
System.out.println("同事类1执行操作");
}
}
具体同事类2:
public class Colleague2 extends AbstractColleague {
public Colleague2(AbstractMediator mediator) {
super(mediator);
}
public void operation(){
System.out.println("同事类2执行操作");
}
}
主入口:
public class Test {
public static void main(String[] args) {
AbstractMediator mediator = new Mediator();
AbstractColleague colleague1 = new Colleague1(mediator);
AbstractColleague colleague2 = new Colleague2(mediator);
mediator.register(colleague1);
mediator.register(colleague2);
colleague1.operation();
colleague1.callColleague(1);
}
}
11、解释器模式:描述如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。此模式由4部分组成:
①抽象表达式:声明对各种类型表达式解析的抽象方法。
public interface Expression {
public String interpret();
}
②非终结符表达式:定义对非终结符表达式解析的抽象方法的实现:
public class WordExpression implements Expression {
private String word;
public WordExpression(String word){
this.word=word;
}
public String interpret(){
return Context.getChineseFromEnglish(word.toLowerCase());
}
}
③终结符表达式:定义对终结符表达式解析的抽象方法的实现:
public class SymbolExpression implements Expression {
private String symbol;
public SymbolExpression(String symbol){
this.symbol=symbol;
}
public String interpret(){
String result="";
if(".".equals(symbol))
result="。";
else
result=" ";
return result;
}
}
④环境类:存储一些全局变量信息。
public class Context {
private static Dictionary<String,String> dictionary = new Hashtable<String,String>();
public Context(){
dictionary.put("this", "这");
dictionary.put("is", "是");
dictionary.put("an", "一个");
dictionary.put("apple", "苹果");
dictionary.put("that", "那");
dictionary.put("pear", "梨");
dictionary.put("a", "一个");
}
public static String getChineseFromEnglish(String english){
return dictionary.get(english);
}
public String convert(String str){
List<Expression> elementList = new ArrayList<Expression>();
String[] elements = str.split("\\.");
for(String tmpElement:elements){
String[] words = tmpElement.split(" ");
for(String tmpWord:words){
elementList.add(new WordExpression(tmpWord));
}
elementList.add(new SymbolExpression("."));
}
StringBuffer sb = new StringBuffer();
for(Expression expression:elementList){
sb.append(expression.interpret());
}
return sb.toString();
}
}
主入口:
public class Test {
public static void main(String[] args) {
String str="This is an apple.That is a pear.";
Context context = new Context();
String result = context.convert(str);
System.out.println(result);
}
}