作者:幻好
起源:恒生 LIGHT 云社区
设计模式简介
- 设计模式(Design pattern)代表了最佳的实际,通常被有教训的面向对象的软件开发人员所采纳。设计模式是软件开发人员在软件开发过程中面临的个别问题的解决方案。这些解决方案是泛滥软件开发人员通过相当长的一段时间的试验和谬误总结进去的。
- 设计模式分为 23 种 经典的模式,依据用处咱们又能够分为三大类。别离是创立型模式、结构型模式和行为型模式。
-
创立型模式:
- 创立型模式提供了一种在创建对象的同时暗藏创立逻辑的形式,而不是应用 new 运算符间接实例化对象。这使得程序在判断针对某个给定实例须要创立哪些对象时更加灵便。
-
结构型模式:
- 结构型模式旨在通过扭转代码构造来达到解耦的目标,使得咱们的代码容易保护和扩大。
-
行为型模式:
- 行为型模式关注的是各个类之间的相互作用,将职责划分分明,使得咱们的代码更加地清晰。
设计模式的六大准则
1. 开闭准则(Open Close Principle)
开闭准则的意思是:对扩大凋谢,对批改敞开。在程序须要进行拓展的时候,不能去批改原有的代码,实现一个热插拔的成果。简言之,是为了使程序的扩展性好,易于保护和降级。想要达到这样的成果,咱们须要应用接口和抽象类,前面的具体设计中咱们会提到这点。
2. 里氏代换准则(Liskov Substitution Principle)
里氏代换准则是面向对象设计的根本准则之一。里氏代换准则中说,任何基类能够呈现的中央,子类肯定能够呈现。LSP 是继承复用的基石,只有当派生类能够替换掉基类,且软件单位的性能不受到影响时,基类能力真正被复用,而派生类也可能在基类的根底上减少新的行为。里氏代换准则是对开闭准则的补充。实现开闭准则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换准则是对实现抽象化的具体步骤的标准。
3. 依赖倒转准则(Dependence Inversion Principle)
这个准则是开闭准则的根底,具体内容:针对接口编程,依赖于形象而不依赖于具体。
4. 接口隔离准则(Interface Segregation Principle)
这个准则的意思是:应用多个隔离的接口,比应用单个接口要好。它还有另外一个意思是:升高类之间的耦合度。由此可见,其实设计模式就是从大型软件架构登程、便于降级和保护的软件设计思维,它强调升高依赖,升高耦合。
5. 迪米特法令,又称起码晓得准则(Demeter Principle)
起码晓得准则是指:一个实体该当尽量少地与其余实体之间产生相互作用,使得零碎功能模块绝对独立。
6. 合成复用准则(Composite Reuse Principle)
合成复用准则是指:尽量应用合成 / 聚合的形式,而不是应用继承。
罕用需把握的设计模式
1. 工厂模式(Factory Pattern)
基本概念
工厂模式(Factory Pattern)最罕用的设计模式之一。这种类型的设计模式属于创立型模式,它提供了一种创建对象的最佳形式。
在工厂模式中,咱们在创建对象时不会对客户端裸露创立逻辑,并且是通过应用一个独特的接口来指向新创建的对象。
用意:定义一个创建对象的接口,让其子类本人决定实例化哪一个工厂类,工厂模式使其创立过程提早到子类进行。
次要解决:次要解决接口抉择的问题。
何时应用:咱们明确地打算不同条件下创立不同实例时。
如何解决:让其子类实现工厂接口,返回的也是一个形象的产品。
代码示例
public interface Shape {void draw();
}
public class Circle implements Shape {
@Override
public void draw() {System.out.println("画个圆形");
}
}
public class CircleFactory implements Shape {
@Override
public void draw() {System.out.println("应用简略工厂模式创立圆");
}
}
public static void main(String[] args) {Shape shape = new CircleFactory();
shape.draw();}
2. 单例模式(Singleton Pattern)
基本概念
单例模式(Singleton Pattern)是 Java 中最简略的设计模式之一。这种类型的设计模式属于创立型模式,它提供了一种创建对象的最佳形式。
这种模式波及到一个繁多的类,该类负责创立本人的对象,同时确保只有单个对象被创立。这个类提供了一种拜访其惟一的对象的形式,能够间接拜访,不须要实例化该类的对象。
单例模式的特点:
- 单例类只能有一个实例。
- 单例类必须本人创立本人的惟一实例。
- 单例类必须给所有其余对象提供这一实例。
用意:保障一个类仅有一个实例,并提供一个拜访它的全局拜访点。
次要解决:一个全局应用的类频繁地创立与销毁。
何时应用:当您想管制实例数目,节俭系统资源的时候。
如何解决:判断零碎是否曾经有这个单例,如果有则返回,如果没有则创立。
代码示例
// 必须把握的单例模式的写法
/**
* 懒汉非线程平安
*/
public static class LazyNosafe{
private static LazyNosafe lazyNosafe;
public static LazyNosafe getLazyNosafe(){lazyNosafe = new LazyNosafe();
return lazyNosafe;
}
}
/**
* 懒汉线程平安
*/
public static class LazySafe{
private static LazySafe lazySafe;
synchronized public static LazySafe getLazyNosafe(){lazySafe = new LazySafe();
return lazySafe;
}
}
/**
* 饿汉模式
*/
public static class HungerSingle{private static HungerSingle hungerSingle = new HungerSingle();
public static HungerSingle getHungerSingle(){return hungerSingle;}
}
/**
* 饿汉模式变种
*/
public static class HungerSingleOther{
private static HungerSingleOther hungerSingleOther;
static {hungerSingleOther = new HungerSingleOther();
}
public static HungerSingleOther getHungerSingleOther(){return hungerSingleOther;}
}
/**
* DCL 双重查看
*/
public static class DclSingleton{
private static DclSingleton dclSingleton;
public static DclSingleton getDclSingleton(){if(dclSingleton != null){synchronized (dclSingleton){if(dclSingleton != null){dclSingleton = new DclSingleton();
}
}
}
return dclSingleton;
}
}
/**
* DCL 双重查看,优化版
*/
public static class DclSingletonOther{
// 通过 volatile 禁止指令重排,保障按程序加载
private static volatile DclSingleton dclSingleton;
public static DclSingleton getDclSingleton(){if(dclSingleton != null){synchronized (dclSingleton){if(dclSingleton != null){dclSingleton = new DclSingleton();
}
}
}
return dclSingleton;
}
}
/**
* 动态外部类
* 利用了 classloader 机制来保障初始化 instance 时只有一个线程
*/
public static class StaticClassSingleton{
private static class StaticSingleton{public static final StaticSingleton staticSingleton = new StaticSingleton();
}
public static StaticSingleton getStaticSingleton(){return StaticSingleton.staticSingleton;}
}
/**
* 枚举的形式
*/
public enum EnumSingleton{INSTANCE;}
3. 代理模式(Proxy Pattern)
基本概念
代理模式(Proxy Pattern)中,一个类代表另一个类的性能。这种类型的设计模式属于结构型模式。
在代理模式中,咱们创立具备现有对象的对象,以便向外界提供性能接口。
用意:为其余对象提供一种代理以管制对这个对象的拜访。
次要解决:在间接拜访对象时带来的问题,比如说:要拜访的对象在近程的机器上。在面向对象零碎中,有些对象因为某些起因(比方对象创立开销很大,或者某些操作须要安全控制,或者须要过程外的拜访),间接拜访会给使用者或者系统结构带来很多麻烦,咱们能够在拜访此对象时加上一个对此对象的拜访层。
何时应用:想在拜访一个类时做一些管制。
如何解决:减少中间层。
代码示例
public interface Cat {void sayMiao();
void run();}
public class BlackCat implements Cat {
@Override
public void sayMiao() {System.out.println("Black miao");
}
@Override
public void run() {System.out.println("Black run");
}
}
public class PoxyCat implements Cat {private BlackCat blackCat = new BlackCat();
@Override
public void sayMiao() {
// Before todo
blackCat.sayMiao();
// After todo
}
@Override
public void run() {
// Before todo
blackCat.run();
// After todo
}
}
4. 适配器模式(Adapter Pattern)
基本概念
- 适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它联合了两个独立接口的性能。
- 这种模式波及到一个繁多的类,该类负责退出独立的或不兼容的接口性能。举个实在的例子,读卡器是作为内存卡和笔记本之间的适配器。您将内存卡插入读卡器,再将读卡器插入笔记本,这样就能够通过笔记本来读取内存卡。
用意:将一个类的接口转换成客户心愿的另外一个接口。适配器模式使得本来因为接口不兼容而不能一起工作的那些类能够一起工作。
次要解决:次要解决在软件系统中,经常要将一些 ” 现存的对象 ” 放到新的环境中,而新环境要求的接口是现对象不能满足的。
何时应用: 1、零碎须要应用现有的类,而此类的接口不合乎零碎的须要。2、想要建设一个能够重复使用的类,用于与一些彼此之间没有太大关联的一些类,包含一些可能在未来引进的类一起工作,这些源类不肯定有统一的接口。3、通过接口转换,将一个类插入另一个类系中。(比方老虎和走兽,当初多了一个飞虎,在不减少实体的需要下,减少一个适配器,在外面容纳一个虎对象,实现飞的接口。)
如何解决:继承或依赖(举荐)。
代码示例
public interface Cat{void sayMiao();
void run();}
public class animalsAdapter implements Cat{
@Override
public void sayMiao() {}
@Override
public void run() {}
}
public class Dog extends animalsAdapter{
@Override
public void run() {System.out.println("dog run");
}
}
5. 外观模式(Facade Pattern)
基本概念
- 外观模式(Facade Pattern)暗藏零碎的复杂性,并向客户端提供了一个客户端能够拜访零碎的接口。这种类型的设计模式属于结构型模式,它向现有的零碎增加一个接口,来暗藏零碎的复杂性。
- 这种模式波及到一个繁多的类,该类提供了客户端申请的简化办法和对现有零碎类办法的委托调用。
用意:为子系统中的一组接口提供一个统一的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易应用。
次要解决:升高拜访简单零碎的外部子系统时的复杂度,简化客户端之间的接口。
何时应用: 1、客户端不须要晓得零碎外部的简单分割,整个零碎只需提供一个 ” 接待员 ” 即可。2、定义零碎的入口。
如何解决:客户端不与零碎耦合,外观类与零碎耦合。
代码示例
public interface Shape {void draw();
}
public class Circle implements Shape {
@Override
public void draw() {System.out.println("Circle::draw()");
}
}
public class Rectangle implements Shape {
@Override
public void draw() {System.out.println("Rectangle::draw()");
}
}
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
public ShapeMaker() {circle = new Circle();
rectangle = new Rectangle();}
public void drawCircle() {circle.draw();
}
public void drawRentangle() {rectangle.draw();
}
}
6. 策略模式(Strategy Pattern)
基本概念
- 在策略模式(Strategy Pattern)中,一个类的行为或其算法能够在运行时更改。这种类型的设计模式属于行为型模式。
- 在策略模式中,咱们创立示意各种策略的对象和一个行为随着策略对象扭转而扭转的 context 对象。策略对象扭转 context 对象的执行算法。
用意:定义一系列的算法, 把它们一个个封装起来, 并且使它们可互相替换。
次要解决:在有多种算法类似的状况下,应用 if…else 所带来的简单和难以保护。
何时应用:一个零碎有许多许多类,而辨别它们的只是他们间接的行为。
如何解决:将这些算法封装成一个一个的类,任意地替换。
代码示例
public interface Strategy{void draw();
}
public class Circle implements Strategy{
@Override
public void draw() {}
}
public class Rentangle implements Strategy{
@Override
public void draw() {}
}
public class StrategyContext{
private Strategy strategy;
public StrategyContext(Strategy strategy){this.strategy = strategy;}
public void draw(){strategy.draw();
}
}
7. 模板办法模式(Template Pattern)
基本概念
- 在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的办法的形式 / 模板。它的子类能够按须要重写办法实现,但调用将以抽象类中定义的形式进行。这种类型的设计模式属于行为型模式。
用意:定义一个操作中的算法的骨架,而将一些步骤提早到子类中。模板办法使得子类能够不扭转一个算法的构造即可重定义该算法的某些特定步骤。
次要解决:一些办法通用,却在每一个子类都从新写了这一办法。
何时应用:有一些通用的办法。
如何解决:将这些通用算法形象进去。
代码示例
public abstract class AbstractTemplate{public void execute(){init();
dosomething();
end();}
public void init(){System.out.println("初始化");
}
public void dosomething(){}
public void end(){System.out.println("完结执行");
}
}
public class DemoTemplate extends AbstractTemplate{
@Override
public void dosomething() {System.out.println("自定义办法");
}
}
public static void main(String[] args) {AbstractTemplate abstractTemplate = new DemoTemplate();
abstractTemplate.execute();}
8. 观察者模式(Observer Pattern)
基本概念
当对象间存在一对多关系时,则应用观察者模式(Observer Pattern)。比方,当一个对象被批改时,则会主动告诉它的依赖对象。观察者模式属于行为型模式。
用意:定义对象间的一种一对多的依赖关系,当一个对象的状态产生扭转时,所有依赖于它的对象都失去告诉并被自动更新。
次要解决:一个对象状态扭转给其余对象告诉的问题,而且要思考到易用和低耦合,保障高度的合作。
何时应用:一个对象(指标对象)的状态产生扭转,所有的依赖对象(观察者对象)都将失去告诉,进行播送告诉。
如何解决:应用面向对象技术,能够将这种依赖关系弱化。
代码示例
public class Subjects {private List<Observer> observerList = new ArrayList<>();
private String state;
public void attachOb(Observer observer) {observerList.add(observer);
}
public void notifyAllObserver() {for (Observer observer : observerList) {observer.updata();
}
}
public String getState() {return state;}
public void setState(String state) {
this.state = state;
notifyAllObserver();}
}
public abstract class Observer {
protected Subjects subject;
public abstract void updata();}
public class DemoOb extends Observer {public DemoOb(Subjects subject){
this.subject = subject;
subject.attachOb(this);
}
@Override
public void updata() {System.out.println("DemoOb has updated");
}
}
public static void main(String[] args) {Subjects subjects = new Subjects();
Observer ob = new DemoOb(subjects);
subjects.setState("123");
}