作者:幻好
来源: 恒生LIGHT云社区
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
合成复用原则是指:尽量使用合成 / 聚合的方式,而不是使用继承。
工厂模式(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(); }
单例模式(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; }
代理模式(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 } }
**意图:**将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
**主要解决:**主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。
何时使用: 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"); } }
**意图:**为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
**主要解决:**降低访问复杂系统的内部子系统时的复杂度,简化客户端之间的接口。
何时使用: 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(); } }
**意图:**定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
**主要解决:**在有多种算法相似的情况下,使用 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(); } }
**意图:**定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
**主要解决:**一些方法通用,却在每一个子类都重新写了这一方法。
**何时使用:**有一些通用的方法。
**如何解决:**将这些通用算法抽象出来。
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(); }
当对象间存在一对多关系时,则使用观察者模式(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"); }
|