23种设计模式 博客分类: 设计模式 java设计模式
介绍方式(1.描述 2.优缺点 3.应用场景)
创建型模式
一. 工厂方法模式分为三种:
1.普通工厂模式:就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
总结:就是在工厂类中加一个方法,你需要什么类型的实现类,判断完就给你什么实现类。(坏处是你的类型字符串错误的话,就不能正确创建,最好避免掉)
2.多个工厂方法模式:是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
总结:就是在工厂类中加多个方法,每个方法都能创建一个实例返回,看你需要哪种实例。
3. 静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
总结:不需要实例化工厂类,常用第三种模式
二 .抽象工厂模式(Abstract Factory)
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则.
所以,把工厂类也做成接口,要用哪个工厂类实例生成产品就用哪个,拓展性较好!
三.单例模式
单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象在程序中不管如何创建,都只有一个实例,你不能new这个对象,因为构造器是私有的。只有一个公共的方法可以让你获得这唯一 一个实例.
这样的模式有几个好处:
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
缺点:若单例类里的线程安全问题没处理好,会导致本来一个实例的类在程序中却出现多个实例.
应用场景:打印机,任务管理器,回收站
例子:(饿汉式,可保证线程安全)
public class SingletonTest { private final static SingletonTest instance = new SingletonTest(); private SingletonTest() { } public static SingletonTest getInstance() { if (instance == null) { syncInit(); } return instance; } public void updateProperties() { SingletonTest shadow = new SingletonTest(); properties = shadow.getProperties(); } }
四.建造者模式
定义:把一个复杂的对象的构建过程和表示分离,使得同样的构建过程可以形成不同的表示.
UML:
建造者模式将很多功能集成到一个类里,这个类可以创造出比较复杂的东西。所以与工厂模式的区别就是:工厂模式关注的是创建单个产品,而建造者模式则关注创建符合对象,多个部分。因此,是选择工厂模式还是建造者模式,依实际情况而定。
总结:和工厂模式类似,都是生产一个实例,只不过建造者模式生产的实例经过很多功能集中来建造出的一个复杂的实例.
比如我是电脑城的老板,是一个指挥者,我让人组装一部电脑给我拿去卖,我就指挥一个员工组装一台电脑,这时这个员工是建造者,员工会把主板、cpu、硬盘、内存等零件一个一个放进去,组成一部电脑的产品实例,这时有买家来买,买家不需要知道这部电脑的构建过程,只需要用就行了.
2个好处:
1)代码封装好了,易复用
2)用户可以直接创建出一个复杂对象,方便
五. 原型模式
原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。本小结会通过对象的复制,进行讲解。在Java中,复制对象是通过clone()实现(同时又分为深复制和浅复制)
总结:就是复制一个相同的对象出来,浅复制的基本类型会重新创建,但引用类型还是指向原来的类型,而深复制全部变量和实例都是重新创建的。比如要创建的对象都差不多,而创建过程又麻烦时,原型模式就很有用。
public class Prototype implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private String string; private SerializableObject obj; /* 浅复制 */ public Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super.clone(); return proto; } /* 深复制 */ public Object deepClone() throws IOException, ClassNotFoundException { /* 写入当前对象的二进制流 */ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); /* 读出二进制流产生的新对象 */ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); } public String getString() { return string; } public void setString(String string) { this.string = string; } public SerializableObject getObj() { return obj; } public void setObj(SerializableObject obj) { this.obj = obj; } } class SerializableObject implements Serializable { private static final long serialVersionUID = 1L; }
要实现深复制,需要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。
7种结构型模式
一.适配器模式
分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式
类的适配器模式:
核心思想就是:有一个Source类,拥有一个方法,是Targetable接口需要的方法,所以待适配,目标接口是Targetable,通过自定义的Adapter类继承Source和实现接口Targetable,接口就能用到Source的方法,将Source的功能扩展到Targetable里.(Targetable target = new Adapter(); )
对象的适配器模式:
基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题
接口的适配器模式:
有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。
总结一下三种适配器模式的应用场景:
类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一个新类,继承原有的类,实现新的接口即可。
对象的适配器模式:当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行。
接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。
二、装饰模式(Decorator)
顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例.
io的 new FileInputStream(new File("abc.txt"));就用到装饰器模式
装饰器模式的应用场景:
1、需要扩展一个类的功能。
2、动态的为一个对象增加功能,而且还能动态撤销。(继承不能做到这一点,继承的功能是静态的,不能动态增删。)
缺点:产生过多相似的对象,不易排错!
三、代理模式(Proxy)
其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们的想法。
代理模式的应用场景:
如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法:
1、修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。
2、就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式。
使用代理模式,可以将功能划分的更加清晰,有助于后期维护!
四、外观模式(Facade)(也有人叫门面模式)
总结:如CPU,硬盘,内存条,能用一个主板把他们连在一起,同时他们又是相互独立的。
主板就相当于一个facade类。
如果我们没有主板类,那么,CPU、Memory、Disk他们之间将会相互持有实例,产生关系,这样会造成严重的依赖,修改一个类,可能会带来其他类的修改,这不是我们想要看到的,有了主板类,他们之间的关系被放在了主板类里,这样就起到了解耦的作用,这,就是外观模式!
五、桥接模式(Bridge)
桥接模式就是把各自的抽象和具体分开,各自独立变化.
像Driver和mysqlDriver/OracleDriver就是抽象和实现分离
六、组合模式
组合模式有时又叫部分-整体模式在处理类似树形结构的问题时比较方便
这个Node有一个parent,又有多个children ,部分-整体
- public class TreeNode {
- private String name;
- private TreeNode parent;
- private Vector<TreeNode> children = new Vector<TreeNode>();
- ....
- }
未完待续
下一篇: C# WinForm国际化实现的简单方法