文章目录
什么是设计模式
设计模式是一种解决方案,用于解决在软件设计中普遍存在的问题,是前辈们对之前软件设计中反复出现的问题的一个总结
我们学设计模式,是为了学习如果合理的组织我们的代码,如何解耦,如何真正的达到对修改封闭扩展开放的效果,而不是去背诵那些类的集成模式,然后自己记不住,回过头感觉设计模式把代码搞的太复杂,搞反设计模式
常见的模式
单例模式(创建型模式)
- 作用
用于保证一个类有且仅有一个实例,用来解决一个全局使用的类频繁的创建和销毁,从而节约系统资源。- 懒汉型,线程不安全
此方法线程不安全,因此在严格意义上来说不能算作单例模式。
- 懒汉型,线程不安全
public callss singleton {
private static Singleton instance;
private Singletone(){}
public static singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
- 懒汉型,线程安全
该方法通过synchronized关键字保证线程安全,但效率会有所降低。
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
- 饿汉型
饿汉型没有使用Synchronize关键字,因而效率较高,但是没有达到lazy loading的效果
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return instance;
}
}
- 双检锁/双重检验锁
双锁机制保证了线程安全且在大多数情况下保持高性能,达到了lazy loading效果。
public class Singleton {
private volatile static Singleton singleton;
private Singleton(){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class){
singleton = new Singleton();
}
}
return singleton;
}
}
- 静态内部类
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
- 枚举
pubilc enum Singleton{
INSTANCE;
public void whateverMethod(){
}
}
工厂模式(创建型模式)
- 作用
用于创建复制对象,明确地计划不同条件下创建不同的实例。 - 优点
使代码结构清晰,能够更加有效的进行封装。对调用者屏蔽具体的产品实现。降低耦合度。 - 缺点
对于简单对象,使用工厂模式会增加其系统的复杂度。
//产品类接口
interface IProduct {
public void productMethod();
}
//产品类实体
class Product implements IProduct {
public void productMethod() {
System.out.println("产品");
}
}
//工厂类接口
interface IFactory {
public IProduct createProduct();
}
//工厂类实体
class Factory implements IFactory {
public IProduct createProduct() {
return new Product();
}
}
//用户
public class Client {
public static void main(String[] args) {
IFactory factory = new Factory();
IProduct prodect = factory.createProduct();
prodect.productMethod();
}
}
代理模式(结构型模式)
- 作用
为其他对象提供一种代理来控制对某个对象的访问,在一些已有的方法在使用的时候需要对已有的方法进行拓展,可用此模式来完成。 - 优点
职责清晰,有更高的拓展性,更加的智能。 - 缺点
实现代理模式增加了工作量,且通过代理模式访问会使性能降低。
//源对象接口
public interface Sourceable {
public void method();
}
//源对象实现类
public class Source implements Sourceable {
@Override
public void method() {
System.out.println("the original method!");
}
}
//代理类
public class Proxy implements Sourceable {
private Source source;
public Proxy(){
this.source = new Source();
}
@Override
public void method() {
if (source == null){
source = new Source ();
}
source.method();
}
}
装饰器模式(结构性模式)
- 作用
通过一个更加灵活的方式动态的为某一个对象添加一些额外的职责 - 优点
可以再不添加很多子类的情况下拓展类,且装饰类和被装饰类可以独立方法。 - 缺点
多层装饰较为复杂
//需被拓展的类的接口
public interface Shape {
void draw();
}
//需被拓展的类
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}
//创建实现了 Shape 接口的抽象装饰类。
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
//扩展了 ShapeDecorator 类的实体装饰类
public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}
观察者模式(行为型模式)
- 作用
用于在易用和低耦合下实现一个对象改变给其他对象通知的功能。 - 优点
观察者和被观察抽象耦合的。 - 缺点
当观察者较多时,完成通知耗时较长,观察者和被观察是循环依赖时,会导致循环调用,可能会使导致系统崩溃
//创建被观察者
public class Subject {
private List<Observer> observers
= new ArrayList<Observer>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
public void attach(Observer observer){
observers.add(observer);
}
public void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
//创建观察者抽象类
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
//观察者实现类1
public class BinaryObserver extends Observer{
public BinaryObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Binary String: "
+ Integer.toBinaryString( subject.getState() ) );
}
}
//观察者实现类2
public class OctalObserver extends Observer{
public OctalObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Octal String: "
+ Integer.toOctalString( subject.getState() ) );
}
}
//改变被观察者状态
public class ObserverPatternDemo {
public static void main(String[] args) {
Subject subject = new Subject();
new OctalObserver(subject);
new BinaryObserver(subject);
System.out.println("First state change: 15");
subject.setState(15);
System.out.println("Second state change: 10");
subject.setState(10);
}
}
设计模式的六大原则
1、开闭原则
开闭原则:实现热插拔,提高扩展性。
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则
里氏代换原则:实现抽象的规范,实现子父类互相替换
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
3、依赖倒转原则
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
5、迪米特法则
迪米特法则,又称最少知道原则
最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则
合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。