一、软件设计模式的几种分类:

1.1.  创建型

创建对象时,不再由我们直接实例化对象;而是根据特定场景,由程序来确定创建对象的方式,从而保证更大的性能、更好的架构优势。创建型模式主要有简单工厂模式
(并不是23种设计模式之一)、工厂方法、抽象工厂模式、单例模式、生成器模式和原型模式。

<>1.2.  结构型

用于帮助将多个对象组织成更大的结构。结构型模式主要有适配器模式adapter、桥接模式bridge
、组合器模式component、装饰器模式decorator、门面模式、亨元模式flyweight和代理模式proxy。

<>1.3.  行为型

用于帮助系统间各对象的通信,以及如何控制复杂系统中流程。行为型模式主要有命令模式command、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式
、状态模式state、策略模式、模板模式和访问者模式。

二、常用的设计模式介绍

2.1.  单例模式(singleton)

     
有些时候,允许自由创建某个类的实例没有意义,还可能造成系统性能下降。如果一个类始终只能创建一个实例,则这个类被称为单例类,这种模式就被称为单例模式。

   
一般建议单例模式的方法命名为:getInstance(),这个方法的返回类型肯定是单例类的类型了。getInstance方法可以有参数,这些参数可能是创建类实例所需要的参数,当然,大多数情况下是不需要的。
public class Singleton { private static Singleton singleton; private
Singleton() { } public static Singleton getInstance() { if (singleton == null)
{ singleton = new Singleton(); } return singleton; } }
优点: 
    1.在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就
防止其它对象对自己的实例化,确保所有的对象都访问一个实例 
    2.单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。 
    3.提供了对唯一实例的受控访问。 
    4.由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。 
    5.允许可变数目的实例。 
    6.避免对共享资源的多重占用。 
缺点: 
    1.不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。 
    2.由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。 
    3.单例类的职责过重,在一定程度上违背了“单一职责原则”。 
   
4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。 
使用注意事项: 
    1.使用时不能用反射模式创建单例,否则会实例化一个新的对象 
    2.使用懒单例模式时注意线程安全问题 
    3.单例模式和懒单例模式构造方法都是私有的,因而是不能被继承的,有些单例模式可以被继承(如登记式模式) 
适用场景: 
    单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。如: 
    1.需要频繁实例化然后销毁的对象。 
    2.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。 
    3.有状态的工具类对象。 
    4.频繁访问数据库或文件的对象。 
以下都是单例模式的经典使用场景: 
    1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。 
    2.控制资源的情况下,方便资源之间的互相通信。如线程池等。 
应用场景举例: 
   
1.外部资源:每台计算机有若干个打印机,但只能有一个PrinterSpooler,以避免两个打印作业同时输出到打印机。内部资源:大多数软件都有一个(或多个)属性文件存放系统配置,这样的系统应该有一个对象管理这些属性文件 
    2. Windows的TaskManager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows
task manager吗? 不信你自己试试看哦~ 
    3. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。 
    4. 网站的计数器,一般也是采用单例模式实现,否则难以同步。 
    5. 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。 
    6. Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。 
    7.
数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗。 
    8. 多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制。 
    9. 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。 
   10. HttpApplication
也是单位例的典型应用。熟悉ASP.Net(IIS)的整个请求生命周期的人应该知道HttpApplication也是单例模式,所有的HttpModule都共享一个HttpApplication实例. 

2.2.  观察者模式(Observer)

   
 对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。Android中的各种Listener就使用到了这一设计模式,只要用户对手机进行操作,对应的listener就会被通知,并作出响应的处理。 
 

看不懂图的人端着小板凳到这里来,给你举个栗子��:假设有三个人,小美(女,28),老王和老李。小美很漂亮,很风骚,老王和老李是两个中年男屌丝,时刻关注着小美的一举一动。有一天,小美说了一句:我老公今天不在家,一个人好无聊啊~~~,这句话被老王和老李听到了,结果乐坏了,蹭蹭蹭,没一会儿,老王就冲到小美家门口了,于是进门了………
在这里,小美是被观察者,老王和老李是观察者,被观察者发出一条信息,然后被观察者进行相应的处理,看代码:
public interface Person { //老王和老李通过这个接口可以接收到小美发过来的消息 void getMessage(String
s); }
这个接口相当于老王和老李的电话号码,小美发送通知的时候就会拨打getMessage这个电话,拨打电话就是调用接口,看不懂没关系,先往下看
public class LaoWang implements Person { private String name = "老王"; public
LaoWang() { } @Override public void getMessage(String s) {
System.out.println(name + "接到了小美打过来的电话,电话内容是:" + s); } } public class LaoLi
implements Person { private String name = "老李"; public LaoLi() { } @Override
public void getMessage(String s) { System.out.println(name +
"接到了小美打过来的电话,电话内容是:->" + s); } }
代码很简单,我们再看看小美的代码:
public class XiaoMei { List<Person> list = new ArrayList<Person>(); public
XiaoMei(){ } public void addPerson(Person person){ list.add(person); }
//遍历list,把自己的通知发送给所有暗恋自己的人 public void notifyPerson() { for(Person
person:list){ person.getMessage("今天家里就我一个人,你们过来吧,谁先过来谁就能得到我!"); } } }
我们写一个测试类来看一下结果对不对
public class Test { public static void main(String[] args) { XiaoMei xiao_mei
= new XiaoMei(); LaoWang lao_wang = new LaoWang(); LaoLi lao_li = new LaoLi();
//老王和老李在小美那里都注册了一下 xiao_mei.addPerson(lao_wang); xiao_mei.addPerson(lao_li);
//小美向老王和老李发送通知 xiao_mei.notifyPerson(); } }
运行结果我截图了 
 
完美~~~

2.3.  装饰者模式 (Decorator Pattern)

对已有的业务逻辑进一步的封装,使其增加额外的功能,如java中的IO流就使用了装饰者模式,用户在使用的时候,可以任意组装,达到自己想要的效果。 

举个栗子,我想吃三明治,首先我需要一根大大的香肠,我喜欢吃奶油,在香肠上面加一点奶油,再放一点蔬菜,最后再用两片面包加一下,很丰盛的一顿午饭,营养又健康,那我们应该怎么来写代码呢? 
首先,我们需要写一个Food类,让其他所有食物都来继承这个类,看代码:
public class Food { private String food_name; public Food() { } public
Food(String food_name) { this.food_name = food_name; } public String make() {
return food_name; }; }
代码很简单,我就不解释了,然后我们写几个子类继承它:
//面包类 public class Bread extends Food { private Food basic_food; public
Bread(Food basic_food) { this.basic_food = basic_food; } public String make() {
return basic_food.make()+"+面包"; } } //奶油类 public class Cream extends Food {
private Food basic_food; public Cream(Food basic_food) { this.basic_food =
basic_food; } public String make() { return basic_food.make()+"+奶油"; } } //蔬菜类
public class Vegetable extends Food { private Food basic_food; public
Vegetable(Food basic_food) { this.basic_food = basic_food; } public String
make() { return basic_food.make()+"+蔬菜"; } }

这几个类都是差不多的,构造方法传入一个Food类型的参数,然后在make方法中加入一些自己的逻辑,如果你还是看不懂为什么这么写,不急,你看看我的Test类是怎么写的,一看你就明白了
public class Test { public static void main(String[] args) { Food food = new
Bread(new Vegetable(new Cream(new Food("香肠"))));
System.out.println(food.make()); } }

看到没有,一层一层封装,我没从里往外看:最里面我new了一个香肠,在香肠的外面我包裹了一层奶油,在奶油的外面我又加了一层蔬菜,最外面我放的是面包,是不是很形象,哈哈
~ 这个设计模式简直跟现实生活中一摸一样,看懂了吗? 
我们看看运行结果吧 
 
一个三明治就做好了~~~

应用实例:

       1、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。

     
 2、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:多层装饰比较复杂。

适用环境:

(1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

(2)处理那些可以撤消的职责。

(3)当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的
子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

2.4. 适配器模式 

适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。


这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。举个真实的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就可以通过笔记本来读取内存卡。


假设一个手机充电器需要的电压是20V,但是正常的电压是220V,这时候就需要一个变压器,将220V的电压转换成20V的电压,这样,变压器就将20V的电压和手机联系起来了。
public class Test { public static void main(String[] args) { Phone phone = new
Phone(); VoltageAdapter adapter = new VoltageAdapter();
phone.setAdapter(adapter); phone.charge(); } } // 手机类 class Phone { public
static final int V = 220;// 正常电压220v,是一个常量 private VoltageAdapter adapter; //
充电 public void charge() { adapter.changeVoltage(); } public void
setAdapter(VoltageAdapter adapter) { this.adapter = adapter; } } // 变压器 class
VoltageAdapter { // 改变电压的功能 public void changeVoltage() {
System.out.println("正在充电..."); System.out.println("原始电压:" + Phone.V + "V");
System.out.println("经过变压器转换之后的电压:" + (Phone.V - 200) + "V"); } }


适配器模式优点: 1、可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。

缺点: 1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B
接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 2.由于 JAVA
至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

使用场景:有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。

注意事项:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。

2.5. 工厂模式 (Factory Pattern)


就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。

实现方式:

a)     抽象产品类(也可以是接口)

b)     多个具体的产品类

c)     工厂类(包括创建a的实例的方法)

简单工厂模式:一个抽象的接口,多个抽象接口的实现类,一个工厂类,用来实例化抽象的接口
// 抽象产品类 abstract class Car { public void run(); public void stop(); } //
具体实现类 class Benz implements Car { public void run() {
System.out.println("Benz开始启动了。。。。。"); } public void stop() {
System.out.println("Benz停车了。。。。。"); } } class Ford implements Car { public void
run() { System.out.println("Ford开始启动了。。。"); } public void stop() {
System.out.println("Ford停车了。。。。"); } } // 工厂类 class Factory { public static Car
getCarInstance(String type) { Car c = null; if ("Benz".equals(type)) { c = new
Benz(); } if ("Ford".equals(type)) { c = new Ford(); } return c; } } public
class Test { public static void main(String[] args) { Car c =
Factory.getCarInstance("Benz"); if (c != null) { c.run(); c.stop(); } else {
System.out.println("造不了这种汽车。。。"); } } }
工厂方法模式:有四个角色,抽象工厂模式,具体工厂模式,抽象产品模式,具体产品模式。不再是由一个工厂类去实例化具体的产品,而是由抽象工厂的子类去实例化产品
// 抽象产品角色 public interface Moveable { void run(); } // 具体产品角色 public class
Plane implements Moveable { @Override public void run() {
System.out.println("plane...."); } } public class Broom implements Moveable {
@Override public void run() { System.out.println("broom....."); } } // 抽象工厂
public abstract class VehicleFactory { abstract Moveable create(); } // 具体工厂
public class PlaneFactory extends VehicleFactory { public Moveable create() {
return new Plane(); } } public class BroomFactory extends VehicleFactory {
public Moveable create() { return new Broom(); } } // 测试类 public class Test {
public static void main(String[] args) { VehicleFactory factory = new
BroomFactory(); Moveable m = factory.create(); m.run(); } }
 

优点:


工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个
软件体系结构 <http://baike.baidu.com/view/1317046.htm>的优化。

缺点:

由于工厂类集中了所有实例的创建逻辑,违反了高内聚 <http://baike.baidu.com/view/292136.htm>
责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;

2.6. 抽象工厂模式 (Abstract Factory Pattern)

与工厂方法模式不同的是,工厂方法模式中的工厂只生产单一的产品,而抽象工厂模式中的工厂生产多个产品
/抽象工厂类 public abstract class AbstractFactory { public abstract Vehicle
createVehicle(); public abstract Weapon createWeapon(); public abstract Food
createFood(); } //具体工厂类,其中Food,Vehicle,Weapon是抽象类, public class DefaultFactory
extends AbstractFactory{ @Override public Food createFood() { return new
Apple(); } @Override public Vehicle createVehicle() { return new Car(); }
@Override public Weapon createWeapon() { return new AK47(); } } //测试类 public
class Test { public static void main(String[] args) { AbstractFactory f = new
DefaultFactory(); Vehicle v = f.createVehicle(); v.run(); Weapon w =
f.createWeapon(); w.shoot(); Food a = f.createFood(); a.printName(); } }
 

持续更新中。。。。。。

 

 

参考链接:

几种常用的设计模式介绍 <https://blog.csdn.net/XSL1990/article/details/16359289#commentBox>

面试必备:常用的设计模式总结
<https://blog.csdn.net/Wu_Ming0821/article/details/51838078#commentBox>

十种常用的设计模式(大部分自己总结,部分摘抄)
<https://blog.csdn.net/dean_hu/article/details/71195133#t4>

 

 

 

 

 

友情链接
ioDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信