一、7种设计原则
-
开放封闭原则
- 模块应该对扩展开放,对更改封闭
-
依赖倒置原则
- 依赖抽象,抽象的不应该依赖于实现细节(变化),实现细节应该依赖于抽象
-
单一职责原则
- 一个类应该仅有一个引起它变化的原因,应该只有一个职责;
-
里式替换原则
- 子类必须能够替换它们的基类(IS-A);如果调用的是父类的话,那么换成子类也完全可以运行
-
接口隔离原则
- 每一个接口应该是一种角色;多个特定的接口强于一个通用目的的接口
-
合成复用原则
- 尽量使用对象组合,而不是继承来达到复用的目的
-
迪米特法则
-
不要和“陌生人”说话
-
只与你的直接朋友通信
-
从而减少不必要的依赖。
-
二、5种创建型设计模式
1、工厂方法
-
定义:是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
-
结构:
-
优点:
-
用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
-
工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。
-
在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。
-
-
缺点:
- 需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度
- 增加了系统的抽象性和理解难度
-
适用场景:
- 一个类不知道它所需要的对象的类
- 一个类通过其子类来指定创建哪个对象
- 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定
-
代码实现
// 抽象工厂接口 public interface AbstractFactory { Product newProduct(); } // 具体工厂实现类1 public class ConcreteFactory1 implements AbstractFactory { public Product newProduct() { return new ConcreteProduct1(); } } // 具体工厂实现类2 public class ConcreteFactory2 implements AbstractFactory { public Product newProduct() { return new ConcreteProduct2(); } } // 商品接口类 public interface Product { void show(); } // 具体商品实现类1 public class ConcreteProduct1 implements Product{ public void show() { System.out.println("this is product1"); } } // 具体商品实现类2 public class ConcreteProduct2 implements Product { public void show() { System.out.println("this is product2"); } } //测试类 public class Client { public static void main(String[] args) { // 生产product1 AbstractFactory factory1 = new ConcreteFactory1(); Product product1 = factory1.newProduct(); product1.show(); // 生产product2 AbstractFactory factory2 = new ConcreteFactory2(); Product product2 = factory2.newProduct(); product2.show(); } }
2、抽象工厂
-
定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
-
结构:
-
优点:
- 只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为,可以实现高内聚低耦合的设计目的。
- 能够保证客户端始终只使用同一个产品族中的对象。
- 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
-
缺点:
- 难以扩展抽象工厂来生产新种类的产品
- 增加新的工厂和产品族容易,增加新的产品等级结构麻烦
-
适用场景:
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节
- 系统中有多于一个的产品族,而每次只使用其中某一产品族。
- 属于同一个产品族的产品将在一起使用
- 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
-
代码实现:
//抽象工厂接口--可以生产手机或平板电脑 public interface AbstractFactory { Phone getPhone(); Pad getPad(); } //华为工厂,可以生产华为手机和平板 public class HuaweiFactory implements AbstractFactory { public Phone getPhone() { return new HuaweiMate50(); } public Pad getPad() { return new HuaweiMatepad11(); } } //小米工厂,可以生产小米手机和平板 public class XiaomiFactory implements AbstractFactory { public Phone getPhone() { return new XiaoMi12Ultra(); } public Pad getPad() { return new XIaoMiPad5(); } } //平板接口 public interface Pad { void show(); } //具体平板产品——华为matepad11 public class HuaweiMatepad11 implements Pad { public void show() { System.out.println("this. is huawei matepad11"); } } //具体平板产品——小米pad5 public class XIaoMiPad5 implements Pad { public void show() { System.out.println("this is xiaomi pad 5"); } } //手机接口 public interface Phone { void show(); } //具体手机产品——小米12Ultra public class XiaoMi12Ultra implements Phone { public void show() { System.out.println("this is XiaoMi12Ultra"); } } //具体手机产品——华为mate50 public class HuaweiMate50 implements Phone { public void show() { System.out.println("this is mate50"); } } //测试类 public class Client { public static void main(String[] args) { // 生产华为产品 AbstractFactory huaweiFactory = new HuaweiFactory(); Phone mate50 = huaweiFactory.getPhone(); mate50.show(); Pad matepad11 = huaweiFactory.getPad(); matepad11.show(); // 生产小米 AbstractFactory xiaomiFactory = new XiaomiFactory(); Phone mi12Ultra = xiaomiFactory.getPhone(); mi12Ultra.show(); Pad xiaomiPad = xiaomiFactory.getPad(); xiaomiPad.show(); } }
3、单例模式
-
定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
-
结构:
-
优点:
- 提供了对唯一实例的受控访问
- 在系统内存中只存在一个对象,可以节约系统资源
- 允许可变数目的实例
-
缺点:
- 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难
- 单例类的职责过重,在一定程度上违背了“单一职责原则”
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;
-
适用场景:
- 系统只需要一个实例对象
- 客户调用类的单个实例只允许使用一个公共访问点
-
代码实现:
public class Singleton { private static volatile Singleton singleton; public Singleton() { System.out.println(Thread.currentThread().getName() + "ok"); } public static Singleton getInstance() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } } public class Client { public static void main(String[] args) { Singleton singleton1 = Singleton.getInstance(); Singleton singleton2 = Singleton.getInstance(); System.out.println(singleton1 == singleton2); } }
4、建造者模式
-
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
-
结构:
-
优点:
- 用户使用不同的具体建造者即可得到不同的产品对象
- 可以更加精细地控制产品的创建过程
- 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。
- 客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。
-
缺点:
- 如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
-
适用场景:
- 需要生成的产品对象有复杂的内部结构
- 需要生成的产品对象的属性相互依赖,需要指定其生成顺序
- 对象的创建过程独立于创建该对象的类
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品
-
代码实现:
// 指挥者——在此处完成建造者的选择 public class Director { Builder builder; public Director(Builder builder) { this.builder = builder; } public Product construct() { builder.addName(); builder.addColor(); return builder.getProduct(); } } // 产品类 public class Product { String name; String color; @Override public String toString() { return "Product{" + "name='" + name + '\'' + ", color='" + color + '\'' + '}'; } public void setName(String name) { this.name = name; } public void setColor(String color) { this.color = color; } } // 抽象建造者 public abstract class Builder { Product product = new Product(); public abstract void addName(); public abstract void addColor(); public Product getProduct() { return product; } } // 具体建造者A public class ConcreteBuilderA extends Builder{ @Override public void addName() { product.setName("A"); } @Override public void addColor() { product.setColor("red"); } } // 具体建造者B public class ConcreteBuilderB extends Builder{ @Override public void addName() { product.setName("B"); } @Override public void addColor() { product.setColor("blue"); } } // 测试类 public class Client { public static void main(String[] args) { Builder builderA = new ConcreteBuilderA(); Director director = new Director(builderA); Product product = director.construct(); System.out.println(product); } }
5、原型模式
-
定义:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
-
结构:
-
优点:
- 简化对象的创建过程,通过一个已有实例可以提高新实例的创建效率。
- 可以动态增加或减少产品类。
- 原型模式提供了简化的创建结构。
- 可以使用深克隆的方式保存对象的状态。
-
缺点:
- 需要为每一个类配备一个克隆方法
- 实现深克隆时需要编写较为复杂的代码
-
适用场景:
- 创建新对象成本较大
- 系统要保存对象的状态
- 需要避免使用分层次的工厂类来创建分层次的对象
-
代码实现(浅克隆):
public class Prototype implements Cloneable { private String name; private String id; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Prototype{" + "name='" + name + '\'' + ", id='" + id + '\'' + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } } public class Client { public static void main(String[] args) throws CloneNotSupportedException { Prototype prototype = new Prototype(); prototype.setId("1"); prototype.setName("Test"); Prototype clone = (Prototype) prototype.clone(); System.out.println(clone); } }