佳礼资讯网

 找回密码
 注册

ADVERTISEMENT

查看: 1110|回复: 15

decoupling sample

[复制链接]
发表于 21-12-2008 06:15 PM | 显示全部楼层
原帖由 mokth 于 21-12-2008 05:40 PM 发表
太HIGH LEVEL 了, 可以简单解释你的diagram 吗? 谢谢你的分享.


不好意思,功力尚浅,所以画到很烂
架设Provider[Core Web Services] 有 3 个Private Method (Method A, Method B, Method C), 和一个Public 的Method (称之为 Interface, 别误会这个Interface)
当任何一个Application (X, Y , Z) [Consumer] 要consume Provider 的任何一个Method时,是必须通过一个或多个Intermediate Web Service (Intermediate WS 只不过是跳板而已,因为Provider 和 Consumer 是没有直接的联系,而需要通过几个Server,所以Intermidiate WS 就安装在这些Server 上)
目前的做法是,Intermediate上也会有三个对应的Method (问题所在,当Provider 有新增Method, 我就得修改所有的Intermediate)
我的解决方法就是在Intermediate 里,就只有一个通用的Method. Application就只是Call这个Method (Method Param: method name & params),然后这个Method就会Call provider 的 Interface.
Interface,就根据param 上的 method name 而决定执行那个 Method, 然后把Result return 回.
希望你能够明白,我表达能力很烂
回复

使用道具 举报


ADVERTISEMENT

 楼主| 发表于 21-12-2008 02:11 PM | 显示全部楼层 |阅读模式
1. Common Solution
using System;
using System.Collections.Generic;
using System.Text;

namespace Transport.Common
{
    public interface ITransport
    {
        void Connect();
        void Disconnect();
        bool SendFile(string filename);
        int ReceiveFiles();
    }
}

2.SMTPTransport Solution
using System;
using System.Collections.Generic;
using System.Text;
using Transport.Common;

namespace Transport
{
    public class SMTPTransport
    {
        #region ITransport Members

        public void Connect()
        {
            //actual implementation
            Console.WriteLine("Connecting via SMTP....";
        }

        public void Disconnect()
        {
            //actual implementation
            Console.WriteLine("Disconnecting via SMTP....";
        }

        public bool SendFile(string filename)
        {
            //actual implementation
            Console.WriteLine("Send file {0} via SMTP....",filename);
            return true;
        }

        public int ReceiveFiles()
        {
            //actual implementation
            Console.WriteLine("Receiving file via SMTP....";
            return 0;
        }

        #endregion
    }
}


3.HTTPTransport Solution
using System;
using System.Collections.Generic;
using System.Text;
using Transport.Common;
namespace Transport
{
    public class HTTPTransport
    {
        #region ITransport Members
        public void Connect()
        {
            //actual implementation
            Console.WriteLine("Connecting via HTTP....";
        }
        public void Disconnect()
        {
            //actual implementation
            Console.WriteLine("Disconnecting via HTTP....";
        }
        public bool SendFile(string filename)
        {
            //actual implementation
            Console.WriteLine("Send file {0} via HTTP....",filename);
            return true;
        }
        public int ReceiveFiles()
        {
            //actual implementation
            Console.WriteLine("Receiving file via HTTP....";
            return 0;
        }
        #endregion
    }
}
4. TransportManager Solution
using System;
using System.Collections.Generic;
using System.Text;
using Transport.Common;
using System.Reflection;
namespace Transport
{
    public class TransportManager
    {
        public static ITransport getTransport(string transporttype)
        {
            ITransport trpt = null;
            string classname = "Transport." + transporttype;
            try
            {
                Type cType = Type.GetType(classname, false, true);
                if (cType == null)
                {
                                        Assembly assembly = Assembly.Load(transporttype+"Transport";
                    cType = assembly.GetType(classname);
                }
                trpt = (ITransport)Activator.CreateInstance(cType, new object[] {});
                return trpt;
            }
            catch (Exception ex)
            {
                throw new Exception("Unable to load command " + classname, ex);
            }
            return null;
        }
    }
}

5. Client
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using Transport;
using Transport.Common;
namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            string transporttype = ConfigurationManager.AppSettings["TransportType"];
            ITransport trp = TransportManager.getTransport(transporttype);
            trp.Connect();
            trp.SendFile("Myfile.doc";
            trp.ReceiveFiles();
            trp.Disconnect();
            Console.ReadKey();
        }
    }
}
Client.exe.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="TransportType" value="SMTP”/>
  </appSettings>
</configuration>

Steps
1. Build all solutions.
2. Copy the smtptransport.dll and Httptransport.dll into client\bin\debug directory.
3. run client\bin\debug\Cleint.exe
4. Edit client\bin\debug\Cleint.exe.config file, change <add key="TransportType" value="SMTP”/>  to <add key="TransportType" value="HTTP”/> , save.
5. run client\bin\debug\Cleint.exe again.
6. Create another solution call FTPTransport, include the common as reference, and implement the Itransport interface. Make sure the dll name is FTPTransport.dll.
7. Build FTPTransport solution, copy the FTPTransport.dll to client\bin\debug directory.
8. Edit client\bin\debug\Cleint.exe.config file, change <add key="TransportType" value="HTTP”/>  to <add key="TransportType" value="FTP”/> , save.
9. run client\bin\debug\Cleint.exe

以上的Sample可以看出, 很容易implement新的Transport protocol而不必更改CLIENTcode.只不过是更改app.config
file
而已. 而旧的transport protocol要改也一样而不必更改clientcode. 留意以上的solutions,每个solution 都是INDEPENDENT (没有cyclic dependency).这就是decouple的好处. 
回复

使用道具 举报

发表于 21-12-2008 05:05 PM | 显示全部楼层
小弟因为近期发现现用的设计在Future Enhancement & Deployment 方面有很大问题 (High Dependency), 所以重新设计过
由于Consumer 和 Provider 并不是直接连接而是要经过几个Server,所以需要Intermediate来连接
目前的设计是,如果我在Provider加了一个新的Method, 我就的修改intermediate然后从新Deploy在所有Server.
我的设计是intermediate将只有一个Common Method 来连接 Consumer & Provider

这个是我的第一个版本,不过已经修改
如果错了,不要笑我
回复

使用道具 举报

 楼主| 发表于 21-12-2008 05:40 PM | 显示全部楼层

回复 2# sfkwan 的帖子

太HIGH LEVEL 了, 可以简单解释你的diagram 吗? 谢谢你的分享.
回复

使用道具 举报

 楼主| 发表于 21-12-2008 06:57 PM | 显示全部楼层

回复 4# sfkwan 的帖子

明白了. 你的Intermediate Web Service 其实类似FACADE的做法. 你可以试用REFLECTION 来CALL你的PROVIDER的METHOD, 这样一来你就不用每次更改Intermediate Web Service 当你增加PROVIDER 的METHODS.
回复

使用道具 举报

发表于 21-12-2008 07:55 PM | 显示全部楼层
不是很懂.Net, 但这不就是COM概念吗?
回复

使用道具 举报

Follow Us
发表于 21-12-2008 09:48 PM | 显示全部楼层
原帖由 mokth 于 21-12-2008 06:57 PM 发表
明白了. 你的Intermediate Web Service 其实类似FACADE的做法. 你可以试用REFLECTION 来CALL你的PROVIDER的METHOD, 这样一来你就不用每次更改Intermediate Web Service 当你增加PROVIDER 的METHODS.


其实也不是FACADE Pattern, 之前尝试Reflection 在 Provider里, 但做不到 Fully dynamic, 可能我做错了
最主要的原因是, Provider & some Intermediate WS 是要Deploy在别的Vendor所维护的服务器,所以出发点是要Minimize changes
回复

使用道具 举报

 楼主| 发表于 22-12-2008 12:31 AM | 显示全部楼层

回复 7# sfkwan 的帖子

你的Intermediate WS 可以试用以下的reflection 方法. 你的Consumer call 这command,

object result = RunCommand(string asemblyname,string classname,string method,object[] param);
string asemblyname = DLL name without extension (eg SMTPTransport)
string classname      = Full class name (eg Tramsport.SMTP)
string method           = the method u need to invoke (eg connect)
object[] param          = the parameter u need to pass into the method (eg new object[] { "www.cari.com", 80} )
object result  = the result of the method

//Invoke method using reflection
public object RunCommand(string asemblyname,string classname,string method,object[] param)
        {
            object clsinst = null;
            try
            {
                Type cType = Type.GetType(classname, false, true);
                if (cType == null)
                {
                    Assembly assembly = Assembly.Load(asemblyname);
                    cType = assembly.GetType(classname);
                }
                clsinst = Activator.CreateInstance(cType, new object[] { });
                object result = clsinst.GetType().InvokeMember(method, BindingFlags.InvokeMethod, null, clsinst, null);

                return result;
            }
            catch (Exception ex)
            {
                throw new Exception("Unable to load command " + classname, ex);

            }

            return null;
        }

如果你不想CONSUMER pass in 那些CLASSNAME 和DLL NAME, 你可以pass in 一些key,然后在Intermediate WS 同过database或XML File 来获得CLASSNAME 和DLL NAME. 哈哈,这只不过是一个简单的建议. 可能别的高手有更好的建议

[ 本帖最后由 mokth 于 22-12-2008 12:33 AM 编辑 ]
回复

使用道具 举报


ADVERTISEMENT

发表于 22-12-2008 01:24 AM | 显示全部楼层
原帖由 mokth 于 22-12-2008 12:31 AM 发表
你的Intermediate WS 可以试用以下的reflection 方法. 你的Consumer call 这command,

object result = RunCommand(string asemblyname,string classname,string method,object[] param);
string asemblyname =  ...


这个我之前有试过,不过在Load Assembly时出现一些问题
所以我就改成Hardcode Switch Case了,
明天再试过,谢谢你
回复

使用道具 举报

 楼主| 发表于 22-12-2008 12:29 PM | 显示全部楼层

回复 10# jasonmun 的帖子

有研究过,可是SPRINT.NET还不是很成熟.在JAVA 的SPRING就很COOL.关于它的DOCUMENTATION也不多.我相信不久将来SPRINT.NET将是一个很好的FRAMEWORK.拭目以待吧.
回复

使用道具 举报

发表于 22-12-2008 10:57 AM | 显示全部楼层
有听说 Spring .NET吗 ? 听说它也支持.NET的..
前阵子, 看到有本书介绍过..
回复

使用道具 举报

发表于 22-12-2008 09:43 PM | 显示全部楼层
除了SPRING, 我也看好 NHibernate..
也是FOR .Net 的..
回复

使用道具 举报

 楼主| 发表于 23-12-2008 01:35 AM | 显示全部楼层

回复 12# jasonmun 的帖子

NHIBERNATE 是一个很不错的ORM. 我用了三年了. 还有LOG4NET 是一个很不错的LOGGING TOOL

[ 本帖最后由 mokth 于 23-12-2008 01:39 AM 编辑 ]
回复

使用道具 举报

发表于 23-12-2008 02:36 PM | 显示全部楼层
如果不用LOAD ASSEMBLY....不是要重新DEPLOY ntermediate WS???
回复

使用道具 举报

 楼主| 发表于 23-12-2008 05:04 PM | 显示全部楼层

回复 14# aquamax 的帖子

我想是吧. 因为ntermediate WS是direct link to provider. sfkwan, 你的design,对吧?

[ 本帖最后由 mokth 于 23-12-2008 05:14 PM 编辑 ]
回复

使用道具 举报

发表于 23-12-2008 05:07 PM | 显示全部楼层
原帖由 aquamax 于 23-12-2008 02:36 PM 发表
如果不用LOAD ASSEMBLY....不是要重新DEPLOY ntermediate WS???


就是为了不要重新deploy intermediate WS, 所以想要换掉现用的设计
把Intermediate WS改成只有一个method作为连接。
大概如下 (每个Component 都在不同的 Server 而且有防火墙)
Core WS  <=> Intermediate WS 1 <=> Intermediate WS 2 <=> Intermediate WS n.... <=>  Application
回复

使用道具 举报


ADVERTISEMENT

您需要登录后才可以回帖 登录 | 注册

本版积分规则

 

ADVERTISEMENT



ADVERTISEMENT



ADVERTISEMENT

ADVERTISEMENT


版权所有 © 1996-2023 Cari Internet Sdn Bhd (483575-W)|IPSERVERONE 提供云主机|广告刊登|关于我们|私隐权|免控|投诉|联络|脸书|佳礼资讯网

GMT+8, 21-12-2025 05:42 AM , Processed in 0.119893 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表