设计模式(一)

151 阅读6分钟

一、设计模式的分类

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

二、设计模式原则

1、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:(1)高层模块不应该依赖低层模块,两者都应该依赖其抽象(2)抽象不应该依赖细节(3)细节应该依赖抽象
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
5、迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承

三、创建型模式

1、单列模式

单列模式主要有这几种
(1)、懒汉模式:只有在真正创建的时候才会加载(按需加载),存在线程安全问题,需要加上线程锁。
(2)、饿汉模式:系统启动完毕即加载成功,没有线程安全方面的问题
(3)、枚举:重点来了、敲黑板了,在上述模式中都会有放射机制和序列化等方式使单列失效,然后用单列模式如下:

public enum  EnumSingleton {
    INSTANCE;
    public EnumSingleton getInstance(){
        return INSTANCE;
    }
}
简单、代码又少、又安全,所以你懂的。
2、工厂方法模式 --(单个产品)
interface Computer{
	void printComputer();
}
class MacbookPro implements Computer{
	public void printComputer(){
		System.out.println("This is a macbookpro");
	}
}
class SurfaceBook implements Computer{
	public void printComputer(){
		System.out.println("This is a Surfacebook");
	}
}

//微软产品工厂
class MsFactory implements ComputerFactory{
	public Computer creatComputer(){
		return new SurfaceBook();
	}
}
//苹果产品工厂
class AppleFactory implements ComputerFactory{
	public Computer creatComputer(){
		return new MacbookPro();
	}
}
//创建对象的接口
interface ComputerFactory{
        Computer creatComputer();}  public class Test19{
	public static void main(String[] args){
		ComputerFactory factory = new AppleFactory();
		Computer computer = factory.creatComputer();
		computer.printComputer();		
	}
}

工厂方法模式:定义一个用来创建对象的接口,让子类决定实例化哪一个工厂。

优点:
降低了代码的耦合度,对象的生成交给子类去完成
实现了开放封闭原则,每次添加子产品不需要修改原有代码
缺点:
增加了代码量,每个具体产品都需要一个具体工厂
当增加抽象产品,也就是添加一个其他产品族,需要修改工厂,

2、抽象工厂模式--(抽象、实现)

interface Computer{
    void printComputer();
}
class MacbookComputer implements Computer{
    public void printComputer(){
        System.out.println("This is a Macbookpro");
    }
}
class SurfaceBookComputer implements Computer {
    public void printComputer() {
        System.out.println("This is a Surfacebook");
    }
}
interface OperatingSystem{
    void printSystem();
}
class MacOsSystem implements OperatingSystem{
    public void printSystem(){
        System.out.println("This is a mac os");
    }
}
class Windows8System implements OperatingSystem{
    public void printSystem() {
        System.out.println("This is a Window 8");
    }
}
interface  ProductionFactory{
    Computer createComputer();
    OperatingSystem createSystem();
}
class AppleFactory implements ProductionFactory{
    public Computer createComputer(){
        return new MacbookComputer();
    }
    public OperatingSystem createSystem(){
        return new MacOsSystem();
    }
}
class MsFactory implements ProductionFactory{
    public Computer createComputer(){
        return new SurfaceBookComputer();
    }
    public OperatingSystem createSystem(){
        return new Windows8System();
    }
}
public class Client{
    public void buyComputer(Computer computer){
        computer.printComputer();
    }
    public void use(OperatingSystem s){
        s.printSystem();
    }

    public static void main(String[] args) {
        Client client = new Client();
        ProductionFactory factory = new AppleFactory();
        Computer computer = factory.createComputer();
        OperatingSystem system = factory.createSystem();
        client.buyComputer(computer);
        client.use(system);
    }
}
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。   工厂方法模式和抽象工厂模式基本类似,可以这么理解:当工厂只生产一个产品时,即为工厂方法模式,而工厂如果生产两个或以上的商品即变为抽象工厂模式。

优点:
代码解耦
实现多个产品族
很好的满足OCP开放封闭原则
对于复杂对象的生产灵活易扩展
缺点:
扩展产品族相当麻烦,因为要修改所有的工厂
由于抽闲工厂模式是工厂方法模式的扩展,总体来说很笨重

4、建造者模式-(组合)

工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。我们看一下代码:

还和前面一样,一个ComputerFactory接口,两个实现类AppleFactoryMsFactory。最后,建造者类如下:

public class Builder {
	private List<ComputerFactory> list = new ArrayList<ComputerFactory>();	public void  AppleComputerFactory(int count){		for(int i=0; i<count; i++){
			list.add(new AppleFactory());		}
	}	
	public void MsComputerFactory(int count){		for(int i=0; i<count; i++){
			list.add(new MsFactory());		}
	}
}

测试类:

public class Test {
 	public static void main(String[] args) {
		Builder builder = new Builder();
		builder.AppleComputerFactory(10);	}
}

从这点看出,建造者模式将很多功能集成到一个类里,这个类可以创造出比较复杂的东西。所以与工程模式的区别就是:工厂模式关注的是创建单个产品,而建造者模式则关注创建符合对象,多个部分。因此,是选择工厂模式还是建造者模式,依实际情况而定。

5、原型模式

原型模式在我们的实际开发中使用场景也是很多的,我在实际开发中主要有以下两大场景:

1、在我们希望接下来这个类的操作与之前这个类的操作之间相互不影响;

2、通常在异步操作的时候避免多线程问题,在调用方法的时候不希望被调用方法对对象的操作影响本层的剩余业务逻辑处理;

在需要这样的时候我可以直接new一个对象自己赋值不采用原型模式呢?

当然可以,只要你不嫌麻烦,前辈们为我们提供了原型模式肯定是因为原型模式对我们有大大的好处的,一般来说原型模式给我们带来了以下的好处:

1、程序运行效率:可以节省new创建对象的时间,

2、代码开发效率:可以一个clone()方法搞定,无需复杂的赋值操作

3、代码的稳定性:依次一个一个的进行代码赋值,会不会因为一个Cv操作失误导致一个细微难察觉的代码bug发布出来了呢?

但是在实际开发中就会发现当我们需要使用原型模式的时候还需要去对对象model进行clone这种方式真的不是很友好;

what? 不友好吗?

其次,我只是需要一个克隆对象,还需要去实现一堆复杂的浅克隆,深克隆代码吗?是不是有点太耗费功夫了呢?是的,作为程序员的我就是这么懒;

这时候我们如果用org.springframework.beans.BeanUtils中的copyProperties,直接一行代码,然后就搞定了。

BeanUtils.copyProperties("转换前的类", "转换后的类");  

总结:就实际开发而言:

单列就用枚举(简单实用);
工厂模式,一个容易写,但是难改(工厂方法),一个容易改,但一开始要写的比较详细(抽象工厂);
建造者模式就是把之前的已有的工厂组合一下;
原型模式,其实就是复制,简单点就总结上面的那段代码就好了。