设计模式总结 之 结构型
1.适配器模型
1 目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。
2 需要适配的类(Adaptee):需要适配的类或适配者类。
3 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。
/**
* 适配器模式
* 原有的快速排序和二分排序算法,和目标接口并不相符合
* 一句话描述:Adapter类,通过继承 src类,实现 dst 类接口,完成src->dst的适配。
*/
trait ScoreOperation {
def sort(array: Array[Int]): Array[Int]
def search(array: Array[Int], key: Int): Int
}
/**
* 快速排序
*/
object QuickSort {
def quickSort(array: Array[Int]): Array[Int] = {
if (array.length < 1) array
else {
val mid = array(array.length / 2)
Array.concat(
quickSort(array.filter(mid > _)),
array.filter(mid == _),
quickSort(array.filter(mid < _)))
}
}
}
//二分查找
object BinarySearch {
//数组是已经排好序的
def binarySearch(array: Array[Int], key: Int): Int = {
var low = 0
var high = array.length - 1
while (low <= high) {
val mid = (low + high) / 2
val midVal = array(mid)
if (midVal > key) {
high = mid - 1
} else if (midVal < key) {
low = mid + 1
} else {
//不能直接 1 ,否则将进入死循环
return 1
}
}
-1
}
}
/**
* 适配器类
*/
object OperationAdpater extends ScoreOperation{
private val sortObj = QuickSort
private val searchObj = BinarySearch
override def sort(array:Array[Int]):Array[Int]=sortObj.quickSort(array)
override def search(array:Array[Int],key :Int):Int=searchObj.binarySearch(array, key)
}
/**
* 测试客户端
* Created by ctao on 2015/8/9.
*/
object Client7 extends App {
//原数组
val sources = Array(84, 76, 50, 69, 90, 91, 88, 86)
//适配器接口
val scoreOperation: ScoreOperation = OperationAdpater
//排序
val result = scoreOperation.sort(sources)
println("成绩排序输出")
result.foreach(x => print(x + ","))
var key = 90
println(s"查找成绩:$key")
println(scoreOperation.search(result,key))
if( scoreOperation.search(result,key) == 1) println(s"找到成绩$key") else println(s"没有找到成绩$key")
key = 89
println(s"查找成绩:$key")
if( scoreOperation.search(result,key) == 1) println(s"找到成绩$key") else println(s"没有找到成绩$key")
}
2.装饰器模式
1.Component(被装饰对象的基类)
定义一个对象接口,可以给这些对象动态地添加职责。
2.ConcreteComponent(具体被装饰对象)
定义一个对象,可以给这个对象添加一些职责。
3.Decorator(装饰者抽象类)
维持一个指向Component实例的引用,并定义一个与Component接口一致的接口。
4.ConcreteDecorator(具体装饰者)
具体的装饰对象,给内部持有的具体被装饰对象,增加具体的职责。
/**
* 装饰模式 java的I/O
* 定义:动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活。
* 设计初衷:通常可以使用继承来实现功能的拓展
* ,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能
* ,这些功能是编译时就确定了,是静态的。
*
*
* 要点: 装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为
*
*
* 结构为
* 1 被装饰接口(Component) 2 被装饰类 (Windows)继承1 3 抽象装饰类(ComponentDecorator(Component))继承1 构造函数含有1
*
* 4 装饰类1(ScrollBarDecorator) 继承3 添加装饰方法到 Component实例中
*/
/**
*
* 抽象界面构件类
*/
/**
* Case Class的特别之处在于:
*
* 编译器会为Case Class自动生成以下方法:
* equals & hashCode
* toString
* copy
* 编译器会为Case Class自动生成伴生对象
* 编译器会为伴生对象自动生成以下方法
*
* apply
* unapply
* 这意味着你可以不必使用new关键字来实例化一个case class.
* case class的类参数在不指定val/var修饰时,会自动编译为val,即对外只读,如果需要case class的字段外部可写,可以显式地指定var关键字
*/
trait Component {
def display(): Unit
}
/**
* 窗口构建类
*/
class Windows extends Component {
override def display(): Unit = println("show Windows")
}
/**
* 构建装饰类
*/
case class ComponentDecorator(component: Component) extends Component {
override def display() = component.display()
}
/**
* 滚动条装饰样例类
*/
class ScrollBarDecorator(component: Component) extends ComponentDecorator(component) {
//自有方法
def scrollBar() = println("add scrollBar")
override def display(): Unit = {
scrollBar()
component.display()
}
}
/**
* 黑色边框装饰类
*/
class BlackBorderDecorator(component: Component) extends ComponentDecorator(component) {
override def display() = {
blackBorder()
super.display()
}
def blackBorder() = println("add blackBorder")
}
object Client10 extends App {
/**
* 窗口
*/
val component: Component = new Windows
/**
* 滚动条来装饰窗口
*/
val componentSB: Component = new ScrollBarDecorator(component)
/**
* 黑色边框装饰滚动条装饰类
*/
val componentBB: Component = new BlackBorderDecorator(componentSB)
componentBB.display()
}
结构分析:
代理角色:代理对象角色内部含有对真实对象的引用 (NEW 一个真实角色进行代理),从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象 可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
import scala.collection.mutable.ArrayBuffer
import java.sql.DriverManager
import scala.collection.mutable
import com.anxin.utils.DBUtil
import java.sql.Connection
import java.sql.ResultSet
import java.sql.PreparedStatement
import java.sql.SQLException
import com.anxin.utils.MySQLDBConn
/**
* 类型:结构模式
*
* 对一些对象提供代理,以限制那些对象去访问其它对象
*
*/
//interface
trait Search {
def doSearch(id: String, pass: String, keyword: String): String
}
//
/**
* 身份验证业务单例对象
*/
object AccessValidator {
/**
* 验证方法
* @param id 查询的id
* @param pass 用户名
* @return 用户是否合法
*/
def validate(id: String, pass: String): Boolean = {
println(s"数据库验证$id 是否为合法用户")
val params = new ArrayBuffer[Any]()
params += id
val result = AccessDAO.checkUser(params)
/**
* 判断result.head获取第一个元素的name和result.head获取第一个元素的pass和传入的id和pass是否一致
* 一致返回true,否则返回false
*/
if (result.head.getOrElse("name", "null") == id && result.head.getOrElse("pass", "null").toString == pass) {
println("登录成功")
true
} else {
println("登录失败")
false
}
}
}
object AccessDAO {
/** * 查询sql */
private val sqlSelect = "select name,pass from user where name = ?"
/** * 查询 * @param params 参数列表 * @return ArrayBuffer */
def checkUser(params: ArrayBuffer[Any]) = MySQLDBConn.Result(sqlSelect, params)
/** * 插入日志列表sql */
private val sqlInsert = "insert into log(userid) values(?)"
/** * 插入操作 * @param params 参数 * @return 受影响行数 */
def insertLog(params: ArrayBuffer[Any]) = MySQLDBConn.updateRow(sqlInsert, params)
}
object Client13 extends App {
}
4.外观模式
例子1:一个电源总开关可以控制四盏灯、一个风扇、一台空调和一台电视机的启动和关闭。该电源总开关可以同时控制上述所有电器设备, 电源总开关即为该系统的外观模式设计。
子系统角色(Subsystem classes) :实现子系统的功能,并处理由Facade对象指派的任务。对子系统而言,facade和client角色是未知的,没有 Facade的任何相关信息;即没有指向Facade的实例。
客户角色(client) :调用facade角色获得完成相应的功能。
import scala.io.Source
import java.io.FileNotFoundException
import java.io.IOException
import java.io.PrintWriter
/**
* 门面(Facade)角色 :客户端可以调用这个角色的方法。此角色知晓相关的(一个或者多个)子系统的功能和责任。
* 在正常情况下,本角色会将所有从客户端发来的请求委派到相应的子系统去。
*
* 子系统(SubSystem)角色 :可以同时有一个或者多个子系统。每个子系统都不是一个单独的类,
* 而是一个类的集合(如上面的子系统就是由ModuleA、ModuleB、ModuleC三个类组合而成)。
* 每个子系统都可以被客户端直接调用,或者被门面角色调用。子系统并不知道门面的存在,对于子系统而言,门面仅仅是另外一个客户端而已。
*/
/**
* 子系统1 读文件
*/
class FileReader {
def read(fileNameSrc:String):String={
var target = ""
try {
for(s <- Source.fromFile(fileNameSrc)){
target += s.toString()
}
} catch {
case io: IOException => io.printStackTrace()
case noFile: FileNotFoundException => noFile.printStackTrace()
}
target
}
}
/**
* 子系统2: 加密文件
*/
class CipherMachine {
def encrypt(plaintText:String):String={
println("数据加密,将明文转化为密文:")
var es = ""
for(i <- 0 until plaintText.length()){
es += String.valueOf(plaintText.charAt(i)%554)
}
es
}
}
/**
* 子系统3: 写文件
*/
class FileWriter{
def write(encryptStr: String, fileNameDes: String):Unit={
print("保存密文,写入文件:")
try {
val out = new PrintWriter(fileNameDes)
out.print(encryptStr)
out.close()
} catch {
case io: IOException => io.printStackTrace()
case noFile: FileNotFoundException => noFile.printStackTrace()
case _ =>println("其他异常")
}
}
}
/**
* 加密外观 门面类
*/
class EncryptFacade{
private val fileReader = new FileReader
private val cipherMachine = new CipherMachine
private val fileWriter = new FileWriter
def fileEncrypt(fileNameSrc: String, fileNameDes: String): Unit = {
fileWriter.write(cipherMachine.encrypt(fileReader.read(fileNameSrc)), fileNameDes)
}
}
object Client11 extends App {
val encryptFacade = new EncryptFacade
encryptFacade.fileEncrypt("G:\\a", "G:\\encrypt")
}
5.桥接模式
由于实际的需要,某个类具有两个或两个以上的维度变化,如果只是用继承将无法实现这种需要,或者使得设计变得相当臃肿。
桥接模式的做法是把变化部分抽象出来,使变化部分与主类分离开来,从而将多个维度的变化彻底分离。最后,提供一个管理类来组合不同维度上的变化,通过这种组合来满足业务的需要。
举个例子,对于笔记本的CPU评测,当安装Intel CPU的时候 评测分数比较高,而安装AMD CPU的时候,则评测分数相对低一些,这个是一唯影响,而配合上电脑品牌,就是二维影响
1.Abstraction
定义抽象类的接口。 维护一个指向Implementor类型对象的指针。
2.RefinedAbstraction
扩充由Abstraction定义的接口。
3.Implementor
定义实现类的接口,该接口不一定要与Abstraction的接口完全一致。 事实上这两个接口可以完全不同。 一般来讲,Implementor接口仅提供 基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作。
4.ConcreteImplementor
实现Implementor接口并定义它的具体实现。
/**
* 图片展示特质
*/
class Matrix //像素矩阵
trait ImageImp{
def doPaint(m:Matrix)
}
class WindowsImp extends ImageImp{
override def doPaint(m:Matrix) = println("show iamge on Windows")
}
class LinuxImp extends ImageImp{
override def doPaint(m:Matrix) = println(" show image on Linux")
}
abstract class Image {
var imageImp : ImageImp
def parseFile(fileName:String)
}
class JPGImage extends Image{
override var imageImp : ImageImp=_
override def parseFile(fileName:String){
imageImp.doPaint(new Matrix)
println(fileName+",格式为JPG")
}
}
class PNGImage extends Image{
override var imageImp: ImageImp = _
override def parseFile(fileName: String) = {
imageImp.doPaint(new Matrix)
println(fileName+",格式为PNG")
}
}
object Client8 extends App {
/**
* 图片
*/
val image: Image = new JPGImage
/**
* 图片展示
*/
val imageImp: ImageImp = new WindowsImp
image.imageImp = imageImp
/**
* 设置文件
*/
image.parseFile("你好")
}
6.组合模式
组合模式使得用户对单个对象和组合对象的使用具有 唯一性 。
/**
* 组合模式 实现文件夹
* 文件夹中包含多种文件类型 或者文件夹
* 功能是对根文件夹进行杀毒
*
* 组合模式:抽象构建 叶子构建(文件) 节点构建(文件夹) 。。叶子构建 节点构建继承抽象构建
*/
//抽象构建
trait AbstractFile {
def add(file: AbstractFile) = println("不支持")
def remove(file: AbstractFile) = println("不支持")
def child(i: Int): AbstractFile = {
println("不支持")
null
}
def killVirus(): Unit
}
//叶子节点1:ImageFile
class ImageFile(name: String) extends AbstractFile {
//def this()是辅助构造函数
override def killVirus(): Unit = println(name + " 杀毒完成")
}
//叶子节点2:文本文件
class TextFile(name: String) extends AbstractFile {
override def killVirus(): Unit = println(name + " 杀毒完成")
}
//节点构造: 文件夹
class Floder(name: String) extends AbstractFile {
var fileList = new ArrayBuffer[AbstractFile]()
override def add(abstractFile: AbstractFile) = fileList += abstractFile
override def remove(abstractFile: AbstractFile) = fileList -= abstractFile
override def child(i: Int) = fileList(i)
override def killVirus(): Unit = {
println(name + " 文件夹 杀毒完成")
for (file <- fileList) {
file.killVirus()
}
}
}
object Client9 extends App{
var rootFloder = new Floder("根目录")
var floder1 = new Floder("tool")
var floder2 = new Floder("workstation")
var file1 = new ImageFile("图片文件1")
var file2 = new TextFile("文本文件1")
floder1.add(file1)
floder2.add(file2)
rootFloder.add(floder1)
rootFloder.add(floder2)
rootFloder.killVirus()
}
7.享元模式
在Flyweight模式中,由于要产生各种各样的对象,所以在Flyweight(享元)模式中常出现Factory模式。Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个对象存储池(Flyweight Pool)来存放内部状态的对象。Flyweight模式是一个提高 程序 效率和性能的模式,会大大加快程序的运行速度.应用场合很多
import scala.collection.mutable
/**
* Flyweight:也就是说在一个系统中如果有多个相同的对象,那么只共享一份就可以了,不必每个都去实例化一个对象
* 单例模式只有一个对象 享元模式有一组对象 从工厂从取时, 工厂有则使用此唯一 若没有工厂则创建一个
*
*/
/**
* 坐标
*/
case class Coordinates(x:Int , y: Int)
/**
* 抽象享元
*/
abstract class IgoChessman{
def color():String
def display(coordinates : Coordinates):Unit={
if(color() == "没有该颜色的棋子"){
println(color())
}else{
println(s"颜色旗子: $color , 位置: ( ${coordinates.x} , ${coordinates.y} )")
}
}
}
/**
* hei
*/
class BlackIgoChessman extends IgoChessman{
override def color()= "Black"
}
class WhiteIgoChessman extends IgoChessman{
override def color() = "White"
}
object IgoChessmanFactory{
private val igoChessmans = new mutable.HashMap[String,IgoChessman]
val black = new BlackIgoChessman
val white = new WhiteIgoChessman
igoChessmans.put("Black", black)
igoChessmans.put("White", white)
def getIgoChessman(color:String)=igoChessmans.getOrElse(color, new IgoChessman{
override def color():String = "no this color"
})
}
/**
* 测试客户端
* Created by ctao on 2015/8/29.
*/
object Client12 extends App {
/**
* 享元工厂
*/
val factory = IgoChessmanFactory
/**
* 黑色棋子1
*/
val black1 = factory.getIgoChessman("Black")
/**
* 黑色棋子2
*/
val black2 = factory.getIgoChessman("Black")
/**
* 黑色棋子3
*/
val black3 = factory.getIgoChessman("Black")
black1.display(Coordinates(1, 2))
black2.display(Coordinates(1, 4))
black3.display(Coordinates(1, 3))
println("判断棋子是否相同:" + black1.eq(black2))
val white1 = factory.getIgoChessman("White")
val white2 = factory.getIgoChessman("White")
white1.display(Coordinates(0,0))
white2.display(Coordinates(1,1))
println("判断棋子是否相同:" + white1.eq(white2))
val error = factory.getIgoChessman("c")
/**
* 错误的请求
*/
error.display(Coordinates(1, 0))
}