网站首页 文章专栏 java设计模式之单例模式与装饰者模式
前言 :java中设计模式经过一代又一代前辈的打磨下,提取出了23种,大体分为三类:创建型模式(5种),结构型模式(7种),行为型模式(11种),今天主要说一下里面的单例模式和装饰者模式。 |

一,设计模式遵循的原则有6个:
1、开闭原则(Open Close Principle)
对扩展开放,对修改关闭。
2、里氏代换原则(Liskov Substitution Principle)
只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
使用多个隔离的借口来降低耦合度。
5、迪米特法则(最少知道原则)(Demeter Principle)
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。继承实际上破坏了类的封装性,超类的方法可能会被子类修改。
二,单例模式
单例模式由分为懒汉式和饿汉式,其中懒汉式又涉及多线程并发问题,下面直接写出代码。
1),饿汉式
public class Singleton {
private Singleton1() {}
private static Singleton1 single = new Singleton1();
public static Singleton getSingletonInstance() {
return single;
}
}2),懒汉式
public class Singleton {
private Singleton(){}
private static volatile Singleton singleton = null; // volatile保证singleton的多线程可见性
public static Singleton getSingletonInstance(){
if(singleton == null){ // 第一次判断是否为null,有必要,里面有锁,防止下一个线程想要获取对象,必须等待上一个线程释放锁之后,才可以继续运行
synchronized (Singleton.class) { // 加锁,防止多线程问题
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}三,装饰者模式
装饰者模式:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。 |
在程序设计时,我们往往会给一个对象的功能加上一些修饰,对原始的功能进行拓展和增强,以来满足我们的需求。
比如我们现在有一个人的类,每个人都有生来的天赋,但是随着人的长大,会慢慢获得一些天赋,我们用装饰者模式演示下。
1),第一种实现
/**
* 定义人类
*/
public class People {
/**
* 每个人都有天赋
*/
public void talent(){
System.out.println("人类天赋之一,会说话!");
}
}然后有个人小明,他长大后获得了唱歌的天赋,我们可以用继承People来获取天赋,并加上唱歌的天赋。
public class XiaoMingTalent extends People{
@Override
public void talent() {
super.talent();
sing();
}
public void sing() {
System.out.println("获得了唱歌天赋!");
}
}随着时间流逝,小明又获得了跳舞的天赋,我们不得不再继承一下。
public class XiaoMingTalent2 extends XiaoMingTalent{
@Override
public void talent() {
super.talent();
dance();
}
public void dance() {
System.out.println("获得了跳舞的天赋");
}
}测试一下,小明的天赋有没有获得。
public class TalentTest {
public static void main(String[] args) {
People xiaoming = new XiaoMingTalent2();
xiaoming.talent();
}
}
看来是可以的。
通过继承就可以给小明增加天赋了,每次继承就给他装饰一下,增加一个天赋,是通过继承父类的方式,重写父类的方法,加上自己的装饰,强化相应的功能。但是这样会出现当小明天赋越来越多时,会不停的继承,会很乱,而且如来再来一个小星也获得了唱歌的天赋,代码就重复了。所以这样虽然实现了装饰,但是效果不好。
如果修饰者修饰过后,可以将这个修饰过的结果传给下一个修饰者,这样的话,就不需要定义这个么多的组合类了,只需要定义相应类型的修饰者就可以了。如果有10 个修饰者的话,只需要定义10 个修饰者的类,然后在实现的时候我们根据需求添加到相应的修饰就可以了。
从上面的的两个个装饰来看,无非是在原有 talent() 方法的基础上添加一些辅助的修饰的功能。
在上面的继承机制上,talent()方法在装饰者定义的时候已经是一个固定功能的了。如果可以将这个talent()方法变为动态的,即运行时确定的行为,然后再在修饰的时候加上相应的修饰就可以了。
一个类要动态绑定某个对象的行为,是持有相应的对象引用,然后在运行时根据这个引用绑定的具体对象,体现出不同的行为,这个就是动态绑定。
依照上面定义的规则,我们可以通过下面来实现,定义一个Arts类,持有一个People对象,只有当运行的时候动态绑定到talent() 方法。然后在这个talent() 方法的基础上进行装饰,加入相应的辅助、增强功能。
public class Arts extends People{
public final People people;
public Arts(People people) {
super();
this.people = people;
}
@Override
public void talent(){
people.talent();
}
}这样的话,如果我们在创建Arts对象的时候,如果传入的People 是已经被修饰过的,即talent()方法是被重写过的,那么我们就可以在此基础上再添新的修饰了。
1>,唱歌天赋的装饰
public class SingTalent extends Arts {
public SingTalent(People people) {
super(people);
}
@Override
public void talent() {
super.talent();
this.sing();
}
public void sing(){
System.out.println("通过修饰-->获得唱歌天赋");
}
}
2>,跳舞天赋的装饰
public class DanceTalent extends Arts {
public DanceTalent(People people) {
super(people);
}
@Override
public void talent() {
super.talent();
this.dance();
}
public void dance(){
System.out.println("通过修饰-->获得跳舞天赋");
}
}以上我们就实现了装饰者模式,我们来测试下,看小明是不是获得了天赋。
public class TalentTest {
public static void main(String[] args) {
People xiaoming = new People();
Arts arts = new Arts(xiaoming);
System.out.println("未装饰之前");
arts.talent();
System.out.println("======================");
System.out.println("第一次装饰唱歌");
arts = new SingTalent(arts);
arts.talent();
System.out.println("======================");
System.out.println("再次装饰跳舞");
arts = new DanceTalent(arts);
arts.talent();
}
}结果如下:

通过这种装饰方式,我们可以很方便地根据具体情况增加修饰者,并且不会产生多余的子类,整个过程很灵活,不像单纯使用类继承的方式会产生很多子类。
People :定义了一个可以被动态添加功能的接口
Arts :持有一个People对象的引用,并且定义了一个和People保持一致的接口。
SingTalent :为People添加功能的角色。
优点:
给一个对象动态地、透明地添加职能,即:不影响其他对象。
动态添加的职能能够被取消。
版权声明:本文由星尘阁原创出品,转载请注明出处!