话不多说,直接切入正题!
设计模式的类型 :
- 创建型模式 :
- 工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式
- 结构型模式 :
- 适配器模式、桥接模式、过滤器模式、组合模式、装饰器模式、外观模式、享元模式、代理模式
- 行为型模式 :
- 责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、空对象模式、策略模式、模板模式、访问者模式
- J2EE模式 :
- MVC模式、业务代表模式、组合实体模式、数据访问对象模式、前端控制器模式、拦截过滤器模式、服务定位器模式、传输对象模式
设计模式的六大原则 :
- 开闭原则 :
- 对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码。为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,需要使用接口和抽象类。
- 里氏代换原则 :
- 子类可以替代父类并且不影响程序的运行,父类才能真正得到复用,并且 子类可以代替父类出现 , 并且子类可以在父类的基础上添加新的行为 ,面向对象思想中,父类和子类的继承关系是抽象化的具体实现。
- 依赖倒转原则 :
- 这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖与具体。
- 接口隔离原则 :
- 使用多个隔离的接口,比使用单个接口要好。他还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
- 迪米特法则,又称最少知道原则 :
- 一个实体应当尽量少地与其他实体之间发生相互作用,是的系统功能模块相互独立。
- 合成复用原则 :
- 尽量使用合成/聚合的方式, 而不是使用继承。
单例模式 (创建型模式):
-
单例模式是一种常用的软件设计模式,在应用这个模式,单例对象的类应保证只有一个实例存在,整个系统只能使用一个对象实例。
-
指由于构造器被 private 修饰被 私有化,应用程序中的实例对象只有一个,没办法去 new 。一般通过 getInstance() 方法获取实例对象。getInstance() 返回的是一个 对象的引用 ,并不是一个新的实例,所以不要错误的理解成多个对象。
- 使用场景: IO 、数据库连接、Redis 连接等。
- 单例模式的优点:
- 在需要频繁创建和销毁对象时,单例模式极大的节约了系统资源,提高了系统性能。
- 由于从始至终只有一个实例对象,因此避免了对共享资源的多重占用。
- 单例模式的缺点:
- 不适用与变化的对象,如果同一类型的对象要在不同的场景发生变化,单例无法保存彼此的状态会导致数据错误。
- 由于单例模式没有抽象层,因此单例类将很难进行拓展。
- 滥用单例将带来一些负面问题,如:为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现 连接池溢出 ;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将 导致对象状态的丢失 。
-
基本写法:只能在单线程下使用,多线程下会产生多个对象
public class Singleton{ private static Singleton singleton; private Singleton(){ } public static Singleton getInstance(){ if(singleton == null){ singleton = new Singleton(); } } return singleton; }
-
懒汉式写法(线程安全)
-
当程序第一次访问单例模式实例时才进行创建(延迟加载)。
public class Singleton{ private static Singleton singleton; private Singleton(){ } // 加锁进行同步,虽然保证了单例,但是效率太低,大量浪费时间 public static synchronized Singleton getInstance(){ if(singleton == null){ singleton = new Singleton(); } } return singleton; }
-
双检锁
-
综合了饿汉与懒汉的优缺点,在锁的内外都加了一层 IF 泰诺健判断
// 采用双重校验锁,这样既保证了线程安全,又比直接上锁提高了执行效率,还节省了内存空间。 public class Singleton{ // volatile关键字来邦正程序运行的有序性,否则多线程访问下可能会出现对象未初始化错误! private volatile static Singleton singleton; private Singleton(){ } public static Singleton getInstance(){ if(singleton == null){ synchronized (Singleton.class){ if(singleton == null){ singleton = new Singleton(); } } } return singleton; } }
-
饿汉式写法
-
第一次引用该类的时候就创建对象实例,而不管实际是否需要创建。
public class Singleton{ private static Singleton instance = new Singleton(); private Singleton(){} private static Singleton getInstance(){ return instance; } }
写法简单,在加载类的时候完成实例化,因此避免了线程同步问题,线程天生安全。但如果程序从始至终都未使用这个对象,就会造成内存的浪费。
-
静态内部类写法 :
-
静态内部类相当于一个静态属性, 只有在第一次加载类时才会初始化 ,在类初始化时,别的线程是无法进入的,因此保证了线程安全。
public class Singleton{ private static class SingletonHolder { private static final Singleton singleton = new Singleton(); } private Singleton(){}; private static final Singleton getInstance(){ return SingletonHolder.singleton } }
简单工厂模式 (创建型模式):
- 建立一个工厂类,对实现了同一接口的一些类进行实例化。实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类的实例。
- 优点:
- 工厂模式是由工厂决定创建哪一个产品实例,客户端可以免除直接创建产品对戏那个的责任,而仅仅消费”产品“,简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
- 客户端只需要传入一些相关参数,具体的实现不需要考虑,通过简单工厂模式可以减少使用者的记忆量。
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体的产品类,在一定程度上提高了系统的灵活性。
- 缺点:
- 不利于拓展,一单添加新的产品类型,就不得不修改工程类的创建逻辑
- 不利于系统维护,当产品类型增多时,工厂类的内部实现将变得复杂,一旦出错可能造成所有产品创建错误。
interface Human{
void sleep;
}
class Man implements Human{
@Override
void sleep(){
System.out.println("man sleep!");
}
}
class Woman implements Human{
@Override
void sleep(){
System.out.println("women sleep!");
}
}
class Simple_Factory{ // 通过反射机制创建对象
public static Human make(Class c){
Human human = null;
try{
human = (Human)Class.forName(c.getName()).getInstance();
}catch(Exception e){
e.println;
}
return human;
}
}
public class Factory{
public static void main(String args[]){
Human man = Simple_Factory.make(Man.class);
man.sleep();
Human woman = Simple_Factory.make(woman.class);
woman.sleep();
}
}
抽象工厂模式 (创建型模式):
-
抽象工厂模式是在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让子类去做决定。例如:饮料生产厂,一开始只生产咖啡,但突然增加了啤酒生产线,开始生产啤酒,如果是简单工厂模式,我们则需要在工厂类中增加生产啤酒的代码,这样的做法既不美观,还不符合软件设计的“开闭原则”。因此借助抽象工厂模式,抽象工厂类只提供生产方法给子类继承,具体的实现交由子类各自完成,这样,如果要新开一个可乐工厂,只需要继承抽象工厂类,并实现其方法,就可以进行拓展,极大的提高了系统的灵活性。
public class AbstractFactoryTest{ public static void main(String args[]){ AbstractFactory coffeFactory = new CoffeFactory(); coffeFactory.createProduct("雀巢"); BeerFactory.createProduct("雪花 "); } // 抽象工厂类 abstract class AbstractFactory{ public abstract String createProduct(String product); } // 子类Coffe class CoffeFactory extends AbstractFactory{ @Override public void createProduct(String product){ if (product == null){ return null; } switch (product){ case "雀巢": System.out.println("生产一罐雀巢咖啡"); break; case "拿铁": System.out.println("生产一罐拿铁咖啡"); break; default: System.out.println("生产一罐其他咖啡"); break; } } } // 子类 Beer class BeerFactory extends AbstractFactory{ @Override public void createProduct(String product){ if (product == null){ return null; } switch (product){ case "雪花": System.out.println("生产一罐雪花啤酒"); break; case "青岛": System.out.println("生产一罐青岛啤酒"); break; default: System.out.println("生产一罐其他啤酒"); break; } } } }
观察者模式 (行为型模式):
-
当对象之间存在一对一或一对多的依赖关系,当一个对象发生变更时,系统会通知其他与之相关联的对象并自动更新。主要解决一个对象发生状态改变时,对其他对象的通知问题,而且要考虑易用和低耦合,保持高度协作。
-
优点:
- 观察者和被观察者是抽象耦合的。
- 观察者模式符合开闭原则。
- 定义了一套稳定的消息更新发送机制。
-
缺点:
- 如果与一个观察目标关联的观察者过多,将观察目标的更新信息通知到所有观察者将花费大量时间。
- 如果在观察者与被观察者之间有循环依赖,观察目标会触发他们的循环调用,将可能导致系统崩溃。
// 抽象的观察者,消息接收方 interface Observe{ public void update(Stirng msg); } class ConcreteObserve implements Observe{ private String name; public ConcreteObserve(String name){ this.name = name; } @Override public void update(String msg){ System.out.println(name + " " + msg); } }
// 抽象被观察者,消息发送方 interface Subject{ public void add(Observe ob); public void del(Observe ob); public void notify(String msg); } class ConcreteSubject implements Subject{ private List<Observe> ObList = new ArrayList<>(); @Override public void add(Observe ob){ ObList.add(ob); } @Override public void del(Observe ob){ ObList.remove(ob); } @Override public void notify(String msg){ for (List ObList : ob){ ob.update(msg); } } }
public class ObserveTest{ public static void main(Stirng args[]){ // 定义发布者 ConcreteSubject concreteSub = new ConcreteSubject(); // 定义观察者 ConcreteObserve concreteOb = new ConcreteObserve("aaa"); ConcreteObserve concreteOb2 = new ConcreteObserve("bbb"); // 添加订阅 concreteSub.add(concreteOb); concreteSub.add(concreteOb2); // 发布消息 concretreSub.notify("更新了"); } }
-
学习设计模式的起因是因为面试需要,还有一点就是实习过程中,在学习公司的项目代码的时候,发现设计模式无处不在。因此决定要好好的吧设计模式学习一遍。
参考链接
https://blog.nowcoder.net/n/ba308e92934a477596878b68d653d203