您的位置:首页 > 其它

设计模式总结 之 结构型

2017-05-02 16:17 260 查看

设计模式总结 之 结构型参考: http://blog.csdn.net/jason0539 设计模式和原则 强烈推荐 http://blog.csdn.net/zhengzhb/article/category/926691 总共有24中设计模式,分为3类: 创建型模式,共六种:单例模式、简单工厂、抽象工厂模式、工厂方法模式、建造者模式、原型模式。结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

1.适配器模型

定义: 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。结构分析:  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) arrayelse {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 = 0var high = array.length - 1while (low <= high) {val mid = (low + high) / 2val 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 = QuickSortprivate val searchObj = BinarySearchoverride 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 = 90println(s"查找成绩:$key")println(scoreOperation.search(result,key))if(  scoreOperation.search(result,key)  == 1) println(s"找到成绩$key") else println(s"没有找到成绩$key")key = 89println(s"查找成绩:$key")if(  scoreOperation.search(result,key)  == 1) println(s"找到成绩$key") else println(s"没有找到成绩$key")}

2.装饰器模式

 动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator模式相比生成子类更为灵活。该模式以对客 户端透明的方式扩展对象的功能。结构分析: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()}
3.代理模式

结构分析:

   抽象角色:声明真实对象和代理对象的共同接口。  代理角色:代理对象角色内部含有对真实对象的引用(NEW 一个真实角色进行代理),从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象        可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。  真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
import scala.collection.mutable.ArrayBufferimport java.sql.DriverManagerimport scala.collection.mutableimport com.anxin.utils.DBUtilimport java.sql.Connectionimport java.sql.ResultSetimport java.sql.PreparedStatementimport java.sql.SQLExceptionimport com.anxin.utils.MySQLDBConn/*** 类型:结构模式** 对一些对象提供代理,以限制那些对象去访问其它对象**///interfacetrait 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 += idval 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:一个电源总开关可以控制四盏灯、一个风扇、一台空调和一台电视机的启动和关闭。该电源总开关可以同时控制上述所有电器设备,电源总开关即为该系统的外观模式设计。结构分析:外观角色(Facade):是模式的核心,他被客户client角色调用,知道各个子系统的功能。同时根据客户角色已有的需求预订了几种功能组合\子系统角色(Subsystem classes):实现子系统的功能,并处理由Facade对象指派的任务。对子系统而言,facade和client角色是未知的,没有Facade的任何相关信息;即没有指向Facade的实例。客户角色(client):调用facade角色获得完成相应的功能。
import scala.io.Sourceimport java.io.FileNotFoundExceptionimport java.io.IOExceptionimport 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 FileReaderprivate val cipherMachine = new CipherMachineprivate val fileWriter = new FileWriterdef fileEncrypt(fileNameSrc: String, fileNameDes: String): Unit = {fileWriter.write(cipherMachine.encrypt(fileReader.read(fileNameSrc)), fileNameDes)}}object Client11 extends App {val encryptFacade = new EncryptFacadeencryptFacade.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 : ImageImpdef 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 WindowsImpimage.imageImp = imageImp/*** 设置文件*/image.parseFile("你好")}

6.组合模式

将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有唯一性。结构分析:1.Component :组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理 Component 的子部件。2.Leaf : 表示叶节点对象。叶子节点没有子节点。3.Composite :定义枝节点行为,用来存储子部件,在 Component 接口中实现与子部件相关的操作。
/***  组合模式 实现文件夹*  文件夹中包含多种文件类型 或者文件夹*  功能是对根文件夹进行杀毒**  组合模式:抽象构建   叶子构建(文件)  节点构建(文件夹) 。。叶子构建  节点构建继承抽象构建*///抽象构建trait AbstractFile {def add(file: AbstractFile) = println("不支持")def remove(file: AbstractFile) = println("不支持")def child(i: Int): AbstractFile = {println("不支持")null}def killVirus(): Unit}//叶子节点1:ImageFileclass 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 += abstractFileoverride def remove(abstractFile: AbstractFile) = fileList -= abstractFileoverride 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.享元模式

在一个系统中如果有多个相同的对象,那么只共享一份就可以了,不必每个都去实例化一个对象。比如说一个文本系统,每个字母定一个对象,那么大小写字母一共就是52个,那么就要定义52个对象。如果有一个1M的文本,那么字母是何其的多,如果每个字母都定义一个对象那么内存早就爆了。那么如果要是每个字母都共享一个对象,那么就大大节约了资源。  在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():Stringdef 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 BlackIgoChessmanval white = new WhiteIgoChessmanigoChessmans.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))}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: