设计模式:单例模式—工厂模式—原型模式 0919
设计模式类别:
设计模式遵循的原则:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经 验的总结。 使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设 计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
总原则:开闭原则
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的 代码,而是要扩展原有代码,实现一个热插拔的效果。
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
这样的设计,能够面对需求改变却可以保持相对稳定,从而使系统在第一个版本以后不断推 出新的版本;面对需求,对程序的改动是通过增加新的代码进行的,而不是更改现有的代码; 所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我 们需要使用接口和抽象类等
1、单一职责原则
定义:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。 问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修 改类T时,有可能会导致原本运行正常的职责P2功能发生故障。
解决方案:遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职 责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使 职责P1发生故障风险。
2、里氏替换原则
里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地 方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功 能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代 换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的 继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构, 通过这个规范的接口与外界交互,子类不应该随便破坏它。
3、依赖倒置原则
定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节 应该依赖抽象。
问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达 成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本 的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者 类C发生联系,则会大大降低修改类A的几率。
4、接口隔离原则
这个原则的意思是:每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接 口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。
接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是 如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度
5、迪米特法则(最少知道原则)
高内聚(类内部的定义尽量紧密)低耦合(类跟类之间的尽量不要有依赖)
就是说:一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应 该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小
的影响该类。
最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋 友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值 中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变 量出现在类中。
6、合成复用原则
尽量使用合成/聚合.避免继承.在新类中应该尽量使用关联关系采用现有的对象,使之成为新对 象的一部分.达到现有功能复用的目的.
通过合成聚合的原则可以降低类于类之间的依赖关系.被依赖的类的修改对其他类的影响相对 小一些.
合成/聚合原则是动态的.可以自由选择使用现有类的那些方法.而继承是静态的,失去了灵活性. 如果父类改变有可能会影响子类的修改,同时破坏了父类的封装性,父类将会暴露不相关的方法给 子类.
单例模式
单例模式(Singleton Pattern)
类型:创建性模式
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。 这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 主要解决:一个全局使用的类频繁地创建与销毁。
使用场景:在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序 对象常被设计成单例。
单例模式的三要素:
Ø 私有的构造方法;
Ø 指向自己实例的私有静态引用;—私有的静态成员变量:数据类型是自己
Ø 以自己实例为返回值的静态的公有方法。—-
单例模式根据实例化对象时机的不同,有两种经典的实现: 一种是 饿汉式单例(立即加载),一种是 懒汉式单例(延迟加载)。
饿汉式单例—代码:
God :
package com.aaa.test1;
/**
* 单例模式:饿汉模式。加同步锁:优点:即实现了懒加载,又保证了线程安全;
*/
public class God {
//定义当前类的静态对象
private static God god = new God();
//设置私有构造
private God(){
System.out.println("调用了God private构造");
}
//对外提供返回对象的方法
public static God getInstance(){
return God.god;
}
//上帝创造世界
public void createWorld(){
System.out.println("上帝创造世界...");
}
}
Test1 :
package com.aaa.test1;
public class Test1 {
public static void main(String[] args) {
God g1 = God.getInstance();
God g2 = God.getInstance();
System.out.println(g1);
System.out.println(g2);
}
}
运行结果:
懒汉式单例—代码:
God :
package com.aaa.test2;
public class God {
private static Object obj = new Object();
//懒汉模式:声明变量,不直接创建
private static God god;
//构造私有
private God(){}
//根据需要创建对象
public static God getInstance(){
//如果对象为空,则创建,否则直接返回。这种方式,多线程并发时会出问题
if(god==null){
//同步锁,双检double check
synchronized (obj) {
if(god==null) {
god = new God();
}
}
}
return god;
}
public void createWold(){
System.out.println("上帝创建世界....");
}
}
Test :
package com.aaa.test2;
public class Test {
public static void main(String[] args) {
// God g1 = God.getInstance();
// God g2 = God.getInstance();
// System.out.println(g1);
// System.out.println(g2);
for (int i=1;i<=100;i++){
new Thread(new Runnable() {
@Override
public void run() {
God god = God.getInstance();
System.out.println(god);
}
}).start();
}
}
}
运行结果:
懒汉模式:静态内部类实现。保证线程安全—代码:
God :
package com.aaa.test3;
/**
* 懒汉模式:静态内部类实现。保证线程安全
*/
public class God {
private God(){
System.out.println("调用了God的private构造");
}
//静态内部类
static class InnerCls{
//内部类种定义静态对象
static God god = new God();
}
//获取静态内部类种的对象
public static God getInstance(){
return InnerCls.god;
}
}
Test :
package com.aaa.test3;
public class Test {
public static void main(String[] args) {
God g1=God.getInstance();
God g2=God.getInstance();
System.out.println(g1);
System.out.println(g2);
}
}
运行结果:
工厂模式
简单工厂(普通工厂)—代码:
ICar :
package com.aaa.test4;
/**
* 定义商品接口:车
*/
public interface ICar {
void run();
}
MiniCar :
package com.aaa.test4;
public class MiniCar implements ICar{
@Override
public void run() {
System.out.println("mini车在跑...");
}
}
SUVCar :
package com.aaa.test4;
public class SUVCar implements ICar{
@Override
public void run() {
System.out.println("SUV车在跑...");
}
}
WuLing :
package com.aaa.test4;
public class WuLing implements ICar{
@Override
public void run() {
System.out.println("五菱之光在跑...");
}
}
CarFactory :
package com.aaa.test4;
/**
* 商品对象工厂:创建各种类型的车
*/
public class CarFactory {
/**
* 根据车的类型来创建
* @param carType
* @return
*/
public static ICar getInstance(String carType){
switch (carType){
case "mini":
return new MiniCar();
case "suv":
return new SUVCar();
case "wl":
return new WuLing();
}
return null;
}
}
Test :
package com.aaa.test4;
public class Test {
public static void main(String[] args) {
//对象的创建在工厂中完成,对使用者隐藏细节。
//使用者根据需要调用工厂方法获取对象
//好处:当对象的创建发生变化时,对使用影响很小
ICar c1 = CarFactory.getInstance("mini");
c1.run();
ICar c2 = CarFactory.getInstance("suv");
c2.run();
ICar c3 = CarFactory.getInstance("wl");
c3.run();
}
}
运行结果:
多个工厂方法模式—代码:
ICar :
package com.aaa.test4;
/**
* 定义商品接口:车
*/
public interface ICar {
void run();
}
MiniCar :
package com.aaa.test4;
public class MiniCar implements ICar{
@Override
public void run() {
System.out.println("mini车在跑...");
}
}
SUVCar :
package com.aaa.test4;
public class SUVCar implements ICar{
@Override
public void run() {
System.out.println("SUV车在跑...");
}
}
WuLing :
package com.aaa.test4;
public class WuLing implements ICar{
@Override
public void run() {
System.out.println("五菱之光在跑...");
}
}
CarFactory :
package com.aaa.test4;
/**
* 商品对象工厂:创建各种类型的车
*/
public class CarFactory {
/**
* 根据车的类型来创建
* @param carType
* @return
*/
public static ICar getInstance(String carType){
switch (carType){
case "mini":
return new MiniCar();
case "suv":
return new SUVCar();
case "wl":
return new WuLing();
}
return null;
}
}
Test :
package com.aaa.test5;
public class Test {
public static void main(String[] args) {
//对象的创建在工厂中完成,对使用者隐藏细节。
//使用者根据需要调用工厂方法获取对象
//好处:当对象的创建发生变化时,对使用影响很小
ICar c1 = CarFactory.getMiniCar();
ICar c2 = CarFactory.getSUVCar();
ICar c3 = CarFactory.getWLCar();
c1.run();
c2.run();
c3.run();
}
}
运行结果:
静态工厂模式—代码(略)
抽象工厂模式—代码:
IFactory :
package com.aaa.test6;
/**
* 抽象工厂
*/
public interface IFactory {
//手机
IPhone createPhone();
//Tv
ITv createTv();
}
IPhone :
package com.aaa.test6;
public interface IPhone {
void call();
}
ITv :
package com.aaa.test6;
public interface ITv {
void show();
}
HuaWeiFactory :
package com.aaa.test6;
public class HuaWeiFactory implements IFactory{
@Override
public IPhone createPhone() {
return new HuaWeiPhone();
}
@Override
public ITv createTv() {
return new HuaWeiTv();
}
}
HuaWeiPhone :
package com.aaa.test6;
public class HuaWeiPhone implements IPhone{
@Override
public void call() {
System.out.println("使用华为手机打电话");
}
}
HuaWeiTv :
package com.aaa.test6;
public class HuaWeiTv implements ITv{
@Override
public void show() {
System.out.println("使用华为电视看大片。。。");
}
}
XiaoMiFactory :
package com.aaa.test6;
public class XiaoMiFactory implements IFactory{
@Override
public IPhone createPhone() {
return new XiaoMiPhone();
}
@Override
public ITv createTv() {
return new XiaoMiTv();
}
}
XiaoMiPhone :
package com.aaa.test6;
public class XiaoMiPhone implements IPhone{
@Override
public void call() {
System.out.println("使用小米手机打电话...");
}
}
XiaoMiTv :
package com.aaa.test6;
public class XiaoMiTv implements ITv{
@Override
public void show() {
System.out.println("使用小米电视看大片...");
}
}
Test :
package com.aaa.test6;
public class Test {
public static void main(String[] args) {
//创建华为工厂,获取华为产品
IFactory f1 = new HuaWeiFactory();
IPhone p1 =f1.createPhone();
ITv t1 = f1.createTv();
p1.call();
t1.show();
IFactory f2 = new XiaoMiFactory();
IPhone p2 = f2.createPhone();
ITv t2 = f2.createTv();
p2.call();
t2.show();
}
}
运行结果:
原型模式—代码:
Dog :
package com.aaa.test7;
public class Dog {
//名字
private String name;
//颜色
private String color;
//年龄
private int age;
//朋友
private Dog friend;
public Dog() {
}
public Dog(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Dog getFriend() {
return friend;
}
public void setFriend(Dog friend) {
this.friend = friend;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", age=" + age +
", friend=" + friend +
'}';
}
}
Test :
package com.aaa.test7;
public class Test {
public static void main(String[] args) {
//原型对象
Dog d1_fiend=new Dog("小白","白色",1);
Dog d1=new Dog("旺财","黄色",2);
d1.setFriend(d1_fiend);
//想要复制一个新狗。这种方式,并没有实际创建新的狗对象。两个变量指向的是同一个狗对象。
//所以根本上,没有实现对象复制效果
Dog d2 = d1;
System.out.println(d1.hashCode());
System.out.println(d2.hashCode());
//System.out.println(d1);
//System.out.println(d2);
System.out.println("===============");
d1.setName("旺旺财");
System.out.println(d1);
System.out.println(d2);
}
}
运行结果:
原型模式:浅拷贝:要真正实现复制效果(克隆),要实现Cloneable和序列化接口—代码:
Dog :
package com.aaa.test8;
import java.io.Serializable;
/**
* 原型模式:要真正实现复制效果(克隆),要实现Cloneable和序列化接口
*/
public class Dog implements Cloneable, Serializable {
//名字
private String name;
//颜色
private String color;
//年龄
private int age;
//朋友
private Dog friend;
public Dog() {
}
public Dog(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Dog getFriend() {
return friend;
}
public void setFriend(Dog friend) {
this.friend = friend;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", age=" + age +
", friend=" + friend +
'}';
}
/**
* 实现克隆接口方法,克隆一个单独的对象。但是此方法的克隆是浅copy模式
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Test :
package com.aaa.test8;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
//原型对象
Dog d1_fiend=new Dog("小白","白色",1);
Dog d1=new Dog("旺财","黄色",2);
d1.setFriend(d1_fiend);
//通过克隆方法实现对象复制,通过测试发现,是两个具有相同属性值的独立对象
//但是这种方式实现的浅copy(只复制了对象的简单属性,对于嵌套的对象属性,并没有实现独立的克隆)
Dog d2 = (Dog) d1.clone();
System.out.println(d1.hashCode());
System.out.println(d2.hashCode());
System.out.println(d1);
System.out.println(d2);
System.out.println("=====================");
d1.setName("旺旺财");
d1.getFriend().setName("小小白"); //修改狗的朋友的信息
System.out.println(d1);
System.out.println(d2);
}
}
运行结果:
原型模式:深拷贝:要真正实现复制效果(克隆),要实现Cloneable和序列化接口—代码:
Dog :
package com.aaa.test9;
import java.io.Serializable;
/**
* 原型模式:要真正实现复制效果(克隆),要实现Cloneable和序列化接口
*/
public class Dog implements Cloneable, Serializable {
//名字
private String name;
//颜色
private String color;
//年龄
private int age;
//朋友
private Dog friend;
public Dog() {
}
public Dog(String name, String color, int age) {
this.name = name;
this.color = color;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Dog getFriend() {
return friend;
}
public void setFriend(Dog friend) {
this.friend = friend;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
", age=" + age +
", friend=" + friend +
'}';
}
/**
* 实现克隆接口方法,克隆一个单独的对象。但是此方法的克隆是浅copy模式
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
CopyUtil :
package com.aaa.test9;
import java.io.*;
public class CopyUtil {
public static Object deepCopy(Object obj) throws IOException, ClassNotFoundException {
//定义内存字节输出流:将字节数组输出到内存的某个区域
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//对象输出字节流:目的是将对象数据,写入到内存字节数组流中
ObjectOutputStream oos = new ObjectOutputStream(bos);
//写对象数据
oos.writeObject(obj);
//创建字节数组输入流,从上面的字节数组输出流中读取字节数据
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
Test :
package com.aaa.test9;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
//原型对象
Dog d1_fiend=new Dog("小白","白色",1);
Dog d1=new Dog("旺财","黄色",2);
d1.setFriend(d1_fiend);
//通过字节数组流的方式,将对象数据写到内存中,然后再复制一份。实现深度copy
Dog d2 = (Dog)CopyUtil.deepCopy(d1);
System.out.println(d1.hashCode());
System.out.println(d2.hashCode());
System.out.println(d1);
System.out.println(d2);
System.out.println("=====================");
d1.setName("旺旺财");
d1.getFriend().setName("小小白"); //修改狗的朋友的信息
System.out.println(d1);
System.out.println(d2);
}
}
运行结果:
注意:
浅拷贝:只能实现值的复制则是浅拷贝;
深度拷贝:能实现嵌套对象的拷贝。
// A code block
var foo = 'bar';
// A code block
var foo = 'bar';
// A code block
var foo = 'bar';
// A code block
var foo = 'bar';
// A code block
var foo = 'bar';
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/118029.html