共计 8422 个字符,预计需要花费 22 分钟才能阅读完成。
1、什么是设计模式
设计模式(Design pattern)是一套被重复应用、少数人通晓的、通过分类编目标、代码设计教训的总结。应用设计模式是为了可重用代码、让代码更容易被别人了解、保障代码可靠性。毫无疑问,设计模式于己于别人于零碎都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。
一些简略的设计模式略过,如常量接口模式、标识类型模式。
以下,将从最简略的设计模式开始讲起:
2、单例模式 Singleton
单例模式是指一个类只能领有惟一的实例。为了保障这一点,咱们必须要限度类的创立。即某个单例类,只能够实例化一次。那怎么才能够做到呢?
实现思路如下:
给须要单例的类申明公有的构造方法。这样就限度了其余类对此类的随便创立。
在单例类外部,申明本人的动态成员变量,且实例化本人。由在以后类中,是能够拜访本人的所有公有成员及办法的,所以,即便构造方法为公有也能够胜利创建对象。
个别状况下,再提供一个静态方法以返回创立的喻一对象。个别状况下,咱们将此办法取名为 newInstace,getInstance 等,不过这并不是硬性的规定。
示例代码如下:
public class SingletonDemo {
// 私有化构造方法
private SingletonDemo(){}
// 申明动态公有成员变量
private static SingletonDemo demo;
// 提供动态工厂办法
public static SingletonDemo getInstance(){if(demo==null){demo = new SingletonDemo();
}
return demo;
}
}
4、多例模式 Multition
既然有单例,就会有多例。多例是指限定一个类的只能创立 N(具体数量)个的设计模式。如以下性别类,就只能创立两个实例。实现思路是在本类中申明多个类的实例,并提供静态方法返回不同的实例即可:
第一种实现:
public class Gender {
private String sex;
private Gender(String sex){this.sex = sex;}
// 男性
private static Gender MALE;
// 女性
private static Gender FEMALE;
public static Gender getMale(){if(MALE==null){MALE = new Gender("男");
}
return MALE;
}
public static Gender getFemale(){if(FEMALE==null){FEMALE = new Gender("女");
}
return FEMALE;
}
}
第二种实现:
public class Gender {
private String sex;
private Gender(String sex){this.sex = sex;}
// 男性
private static Gender MALE;
// 女性
private static Gender FEMALE;
static{// 动态代码块中初始化
MALE = new Gender("男");
FEMALE = new Gender("女");
}
public static Gender getMale(){return MALE;}
public static Gender getFemale(){return FEMALE;}
}
第三种实现:间接应用枚举
public enum Gender{MALE("男"),FEMALE("女");
private String sex;
private Gender(String sex){this.sex=sex;}
@Override
public String toString() {return sex;}
}
5、工厂办法模式 Factory Method
工厂办法指在一个类外部,提供一个静态方法,返回本人的实例或是其余类的实例。具体是返回本人的实例,还是返回其余类的实例,这个要看具体业务的需要。咱们的数据连接池返回的就是其余对象的实例:
public class FactoryDemo{
private static Connection con;
static{
// 在此连贯数据库
con = DriverManager.getConnection(…);
}
// 提供一个动态工厂办法
public static Connection getConn(){return con;}
}
6、适配置器模式 Adapter
一个接口,往往定义很多办法,但实现此接口的类,可能只须要几个办法。那么那些多余的办法,占据了咱们大量的代码,将失去意义。那怎么才能够即省去一些无用的办法,又实现此接口呢?这就是适配置器模式。
Awt 开发中的 Listener 大量应用了此模式。如 WindowListener 和 WindowAdapter。
请见下面两个类(WindowListener 和 WindowAdapter)的源代码。
7、装璜器设计模式 (Decorator) 也叫包装设计模式(Wrapper)
如果一个类,即是某个类的子类,又领有某个类的一个成员变量,则被叫做包装模式。
如:
public Interface IA{} // 定义一个接口
public class B implements IA{ // 首先 B 是 IA 的子类
private IA ia; // 而后 B 领有一个 IA 的成员变量。}
应用装璜器或是包装模式个别是为了加强类的性能。如加强某个办法等。
8、代理模式 Proxy
代理模式的定义:对其余对象提供一种代理以管制对这个对象的拜访。在某些状况下,一个对象不想或者不能间接援用另一个对象,而代理对象能够在客户端和指标对象之间起到中介的作用。
假如有一个 Italk 接口,有空的办法 talk()(谈话),所有的 people 对象都实现(implements)这个接口,实现 talk()办法,前端有很多中央都将 people 实例化,执行 talk 办法,起初发现这些前端里有一些除了要谈话以外还要唱歌(sing),那么咱们既不能在 Italk 接口里减少 sing()办法,又不能在每个前端都减少 sing 办法,咱们只有减少一个代理类 talkProxy,这个代理类里实现 talk 和 sing 办法,而后在须要 sing 办法的客户端调用代理类即可,代码如下:
// 定义接口
interface ITalk {public void talk(String msg);
}
// 定义一个代理,接管 ITalk, 并减少一个办法 sing
class TalkProxy implements ITalk{
private ITalk talker;
private String music;
public TalkProxy(ITalk talker,String music){
this.talker=talker;
this.music = music;
}
@Override
public void talk(String msg) {talker.talk(msg);
sing();}
// 再多定义一个唱歌办法
private void sing(){System.err.println("正在唱:"+music);
}
}
// 接口的一个实现类
class Tom implements ITalk{public void talk(String msg) {System.err.println("正在谈话:"+msg);
}
}
// 测试调用
public class ProxyDemo{public static void main(String[] args) {TalkProxy proxy = new TalkProxy(new Tom(),"十里香");
proxy.talk("Hello");
}
}
9、动静代理 Dync Proxy
在 JDK 中,Proxy 类和 InvocationHandler 能够在不增加任何代码的状况下加强某个办法:
package cn.arcstack.pattern;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
// 测试代码
public class DyncProxyDemo {public static void main(String[] args) {List list =(List) MyProxy.getProxy(new ArrayList());
list.add("Hello");
}
}
// 书写代理类
class MyProxy implements InvocationHandler{
// 申明被代理之前的对象
private Object src;
// 公有构造方法
private MyProxy(Object src){this.src=src;}
// 提供一个静态方法以返回被代理当前的对象
public static Object getProxy(Object src){
Object dest = null;// 被代理当前的对象
try{
// 解决代理的外围代码
dest = Proxy.newProxyInstance(MyProxy.class.getClassLoader(),
src.getClass().getInterfaces(),
new MyProxy(src));
}catch(Exception e){throw new RuntimeException(e.getMessage(),e);
}
return dest;
}
// 拦挡办法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {System.err.println("耿直执行办法:"+method.getName());
Object oo = method.invoke(src, args);
return oo;
}
}
10、观察者模式 Observer
观察者模式又叫做公布订阅模式。在此种模式中,一个指标物件治理所有相依于它的观察者物件,并且在它自身的状态扭转时被动发出通知。这通常透过呼叫各观察者所提供的办法来实现。此种模式通常被用来实作事件处理零碎。如 Awt 中的监听器 Listener 都是采纳了种模式。
在此种模式下,观察者只是一个接口,即定义一个标准,具体的实现应该是客户端实现。就像 Swing 中的注册一个监听器一样如:
JFrame frame = new Jframe();// 申明被察看,被监听者对象
frame.addWindowListener(new WindowListener(){…});// 增加一个实现 WindowListener 的观察者
frame.setVisible(true); // 执行一些后续的操作,只有注册了观察者,就会被观察者所监听到
示例代码如下:
public class ObserverDemo {public static void main(String[] args) {
// 杰克逊对象
Singer jackson = new Singer();
// 注册观察者
jackson.addListener(new SingListener() {public void listener(Singer singer) {System.err.println("监听到了手的正在唱歌。。。。");
}
});
// 唱歌
jackson.sing();}
}
// 设置一个监听器接口 - 监听谁在唱歌
interface SingListener{public void listener(Singer singer);
}
// 一个可能的被监听者
class Singer{
// 申明观察者
private SingListener listener;
public void addListener(SingListener sl){this.listener=sl;}
public void sing(){
// 判断是否有观察者
if(this.listener!=null){this.listener.listener(this);
}
System.err.println("歌手正在唱歌");
}
}
给观察者增加一个察看事件对象,SingEvent, 以便于解藕:
残缺的示例代码如下:
package cn.arcstack.pattern;
// 测试代码
public class ObserverDemo {public static void main(String[] args) {Singer jackson = new Singer();
jackson.addListener(new SingListener() {public void listener(SingEvent event) {System.err.println("歌手是:"+event.getSource());
}
});
jackson.sing();}
}
// 设置一个监听器接口 - 监听谁在唱歌
interface SingListener{public void listener(SingEvent event);
}
// 设计一个事件对象
class SingEvent{
// 接管事件对象,即被观察者
private Object source;
public SingEvent(Object source){this.source=source;}
public Object getSource() {return source;}
}
// 一个可能的被监听者
class Singer{
// 申明观察者
private SingListener listener;
public void addListener(SingListener sl){this.listener=sl;}
public void sing(){
// 判断是否有观察者
if(this.listener!=null){this.listener.listener(new SingEvent(this));
}
System.err.println("歌手正在唱歌"+this);
}
}
11、策略模式 Strategy
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还能够互相替换。策略模式让算法独立于应用它的客户而独立变动。
策略模式的组成
-形象策略角色:策略类,通常由一个接口或者抽象类实现。
-具体策略角色:包装了相干的算法和行为。
-环境角色:持有一个策略类的援用,最终给客户端调用。
package cn.arcstack.pattern;
/**
* 策略模式
*/
public class StrategyDemo {public static void main(String[] args) {Context ctx = new Context(new JavaProgrammer());
ctx.doSth();}
}
// 设计一个公共的接口
interface IStrategy{public void doSth();
}
// 别离书写多个实现类,有不同的实现策略
class JavaProgrammer implements IStrategy{public void doSth() {System.err.println("写 Java 代码");
}
}
class PhpProgrammer implements IStrategy{public void doSth() {System.err.println("写 PHP 代码");
}
}
// 实现策略类
class Context{
private IStrategy strategy;
public Context(IStrategy strategy){this.strategy = strategy;}
// 具体调用
public void doSth(){this.strategy.doSth();
}
12、门面设计模式
门面设计模式的构造:
没有门面设计模式的调用办法:
有了门面设计模式的类框架图如下:即由原来的客户端一一调用每一个零碎,批改成一应用一个对立中调用:
具体实现代码略。
13、命令模式 Command
在软件系统中,“行为请求者”与“行为实现者”通常出现一种“紧耦合”。但在某些场合,比方要对行为进行“记录、撤销 / 重做、事务”等解决,这种无奈抵挡变动的紧耦合是不适合的。在这种状况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为形象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)
示例代码如下:
package cn.arcstack.pattern;
public class CommandDemo {public static void main(String[] args) {
// 命令的接收者只有一个
Receiver receiver = new Receiver();
// 定义命令的执行者
Invoker invoker = new Invoker();
// 通过 Command 类具体告诉命令的接收者做什么工作
invoker.setCommand(new CommandA(receiver));
invoker.execute();
// 再设置第二个命令
invoker.setCommand(new CommandB(receiver));
invoker.execute();}
}
// 定义命令
abstract class Command{
// 定义接管命令对象
protected Receiver receiver;
public Command(Receiver rec){this.receiver=rec;}
public abstract void execute();}
// 指定接收者的工作
class Receiver{public void actionA(){System.err.println("做第一件事");
}
public void actionB(){System.err.println("做第二件事");
}
}
// 执行者
class Invoker{
// 接管一个命令
private Command command;
public void setCommand(Command cmd){this.command = cmd;}
// 执行命令
public void execute(){command.execute();
}
}
// 定义两个具体的命令
class CommandA extends Command{public CommandA(Receiver rec) {super(rec);
}
@Override
public void execute() {this.receiver.actionA();
}
}
// 定义两个具体的命令
class CommandB extends Command{public CommandB(Receiver rec) {super(rec);
}
@Override
public void execute() {this.receiver.actionB();
}
}
14、原型模式 Prototype
用原型实例指定创建对象的品种,并且通过拷贝这些原型创立新的对象。
Prototype 原型模式是一种创立型设计模式,Prototype 模式容许一个对象再创立另外一个可定制的对象,基本无需晓得任何如何创立的细节, 工作原理是: 通过将一个原型对象传给那个要动员创立的对象,这个要动员创立的对象通过申请原型对象拷贝它们本人来施行创立。
它次要面对的问题是:“某些结构复杂的对象”的创立工作;因为需要的变动,这些对象常常面临着激烈的变动,然而他们却领有比较稳定统一的接口。
如何应用?
因为 Java 中的提供 clone()办法来实现对象的克隆,所以 Prototype 模式实现一下子变得很简略。
代码略。
15、亨元模式 flyweight
能够了解成为轻量级模式, 是一种软件设计模式。
面向对象的思维很好地解决了抽象性的问题,个别也不会呈现性能上的问题。然而在某些状况下,对象的数量可能会太多,从而导致了运行时的代价。那么咱们如何去防止大量细粒度的对象,同时又不影响客户程序应用面向对象的形式进行操作?
见上面的代码:
// 应用 Integer 对象的示例
Integer b1 = 100;
Integer b2 = 100;
System.err.println(b1==b2); //true
// 因为大量细粒度的对象呈现在 128 以下,所以,下现的值为 false
Integer b3 = 128;
Integer b4 = 128;
System.err.println(b3==b4); //false
16、总结
在理论的开发中,单例、多例、工厂、适配置器、代理、装璜、包装是常常应用的发模式,其余模式只须要理解就能够了。
本文由 mdnice 多平台公布